Skip to content

Commit

Permalink
Feat/custom log file (#9)
Browse files Browse the repository at this point in the history
* remove healthcheck for bad configure ingress with wildcard

* feat: add a way to configure log path
  • Loading branch information
SoulKyu committed Jul 4, 2024
1 parent 821ce3a commit e7d67d6
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 29 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Yggdrasil can be configured using a config file e.g:
{
"nodeName": "foo",
"ingressClasses": ["multi-cluster", "multi-cluster-staging"],
"accessLog": "/var/log/envoy/",
"syncSecrets": false,
"certificates": [
{
Expand Down Expand Up @@ -197,6 +198,7 @@ The Yggdrasil-specific metrics which are available from the API are:
--config string config file
--config-dump Enable config dump endpoint at /configdump on the health-address HTTP server
--debug Log at debug level
--access-log path for the file logs
--envoy-listener-ipv4-address strings IPv4 addresses by the envoy proxy to accept incoming connections (default "0.0.0.0")
--envoy-port uint32 port by the envoy proxy to accept incoming connections (default 10000)
--health-address string yggdrasil health API listen address (default "0.0.0.0:8081")
Expand Down
5 changes: 5 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type config struct {
NodeName string `json:"nodeName"`
Clusters []clusterConfig `json:"clusters"`
SyncSecrets bool `json:"syncSecrets"`
AccessLog string `json:"accessLog"`
Certificates []envoy.Certificate `json:"certificates"`
TrustCA string `json:"trustCA"`
UpstreamPort uint32 `json:"upstreamPort"`
Expand Down Expand Up @@ -79,6 +80,7 @@ func init() {
rootCmd.PersistentFlags().String("address", "0.0.0.0:8080", "yggdrasil envoy control plane listen address")
rootCmd.PersistentFlags().String("health-address", "0.0.0.0:8081", "yggdrasil health API listen address")
rootCmd.PersistentFlags().String("node-name", "", "envoy node name")
rootCmd.PersistentFlags().String("access-log", "/var/log/envoy/", "envoy default access log file")
rootCmd.PersistentFlags().String("cert", "", "certfile")
rootCmd.PersistentFlags().String("key", "", "keyfile")
rootCmd.PersistentFlags().String("ca", "", "trustedCA")
Expand Down Expand Up @@ -119,6 +121,7 @@ func init() {
viper.BindPFlag("address", rootCmd.PersistentFlags().Lookup("address"))
viper.BindPFlag("healthAddress", rootCmd.PersistentFlags().Lookup("health-address"))
viper.BindPFlag("nodeName", rootCmd.PersistentFlags().Lookup("node-name"))
viper.BindPFlag("accessLog", rootCmd.PersistentFlags().Lookup("access-log"))
viper.BindPFlag("ingressClasses", rootCmd.PersistentFlags().Lookup("ingress-classes"))
viper.BindPFlag("cert", rootCmd.PersistentFlags().Lookup("cert"))
viper.BindPFlag("key", rootCmd.PersistentFlags().Lookup("key"))
Expand Down Expand Up @@ -240,6 +243,7 @@ func main(*cobra.Command, []string) error {
c.Certificates,
viper.GetString("trustCA"),
viper.GetStringSlice("ingressClasses"),
viper.GetString("accessLog"),
envoy.WithUpstreamPort(uint32(viper.GetInt32("upstreamPort"))),
envoy.WithEnvoyListenerIpv4Address(viper.GetStringSlice("envoyListenerIpv4Address")),
envoy.WithEnvoyPort(uint32(viper.GetInt32("envoyPort"))),
Expand All @@ -256,6 +260,7 @@ func main(*cobra.Command, []string) error {
envoy.WithTracingProvider(viper.GetString("tracingProvider")),
envoy.WithAlpnProtocols(viper.GetStringSlice("alpnProtocols")),
)
configurator.ValidateAndFormatPath()
snapshotter := envoy.NewSnapshotter(envoyCache, configurator, aggregator)

go snapshotter.Run(aggregator)
Expand Down
13 changes: 7 additions & 6 deletions pkg/envoy/boilerplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package envoy
import (
"fmt"
"log"
"path/filepath"
"strings"

cal "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3"
Expand Down Expand Up @@ -181,7 +182,7 @@ func makeGrpcLoggerConfig(cfg HttpGrpcLogger) *gal.HttpGrpcAccessLogConfig {
}
}

func makeFileAccessLog(cfg AccessLogger) *eal.FileAccessLog {
func makeFileAccessLog(cfg AccessLogger, accessLog string) *eal.FileAccessLog {
format := DefaultAccessLogFormat
if len(cfg.Format) > 0 {
format = cfg.Format
Expand All @@ -194,7 +195,7 @@ func makeFileAccessLog(cfg AccessLogger) *eal.FileAccessLog {
jsonFormat = b.GetStructValue()

accessLogConfig := &eal.FileAccessLog{
Path: "/var/log/envoy/access.log",
Path: filepath.Join(accessLog, "access.log"),
AccessLogFormat: &eal.FileAccessLog_LogFormat{
LogFormat: &core.SubstitutionFormatString{
Format: &core.SubstitutionFormatString_JsonFormat{
Expand All @@ -217,9 +218,9 @@ func makeZipkinTracingProvider() *tracing.ZipkinConfig {
return zipkinTracingProviderConfig
}

func (c *KubernetesConfigurator) makeConnectionManager(virtualHosts []*route.VirtualHost) (*hcm.HttpConnectionManager, error) {
func (c *KubernetesConfigurator) makeConnectionManager(virtualHosts []*route.VirtualHost, accessLog string) (*hcm.HttpConnectionManager, error) {
// Access Logs
accessLogConfig := makeFileAccessLog(c.accessLogger)
accessLogConfig := makeFileAccessLog(c.accessLogger, accessLog)
anyAccessLogConfig, err := anypb.New(accessLogConfig)
if err != nil {
log.Fatalf("failed to marshal access log config struct to typed struct: %s", err)
Expand Down Expand Up @@ -309,8 +310,8 @@ func (c *KubernetesConfigurator) makeConnectionManager(virtualHosts []*route.Vir
}, nil
}

func (c *KubernetesConfigurator) makeFilterChain(certificate Certificate, virtualHosts []*route.VirtualHost) (listener.FilterChain, error) {
httpConnectionManager, err := c.makeConnectionManager(virtualHosts)
func (c *KubernetesConfigurator) makeFilterChain(certificate Certificate, virtualHosts []*route.VirtualHost, accessLog string) (listener.FilterChain, error) {
httpConnectionManager, err := c.makeConnectionManager(virtualHosts, accessLog)
if err != nil {
return listener.FilterChain{}, fmt.Errorf("failed to get httpConnectionManager: %s", err)
}
Expand Down
35 changes: 28 additions & 7 deletions pkg/envoy/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package envoy
import (
"errors"
"log"
"path/filepath"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -62,6 +63,7 @@ type KubernetesConfigurator struct {
ingressClasses []string
nodeID string
syncSecrets bool
accessLog string
certificates []Certificate
trustCA string
upstreamPort uint32
Expand All @@ -86,21 +88,40 @@ type KubernetesConfigurator struct {
}

// NewKubernetesConfigurator returns a Kubernetes configurator given a lister and ingress class
func NewKubernetesConfigurator(nodeID string, certificates []Certificate, ca string, ingressClasses []string, options ...option) *KubernetesConfigurator {
c := &KubernetesConfigurator{ingressClasses: ingressClasses, nodeID: nodeID, certificates: certificates, trustCA: ca}
func NewKubernetesConfigurator(nodeID string, certificates []Certificate, ca string, ingressClasses []string, accessLog string, options ...option) *KubernetesConfigurator {
c := &KubernetesConfigurator{ingressClasses: ingressClasses, nodeID: nodeID, certificates: certificates, trustCA: ca, accessLog: accessLog}
for _, opt := range options {
opt(c)
}
return c
}

func (c *KubernetesConfigurator) ValidateAndFormatPath() {
if c.accessLog == "" {
logrus.Fatal("accessLog path cannot be empty")
}

// Clean the path and make it absolute
c.accessLog = filepath.Clean(c.accessLog)
absolutePath, err := filepath.Abs(c.accessLog)
if err != nil {
logrus.Fatalf("invalid path: %v", err)
}
c.accessLog = absolutePath

// Ensure the path ends with a directory separator if it's a directory
if strings.HasSuffix(c.accessLog, string(filepath.Separator)) {
c.accessLog = string(filepath.Separator)
}
}

// Generate creates a new snapshot
func (c *KubernetesConfigurator) Generate(ingresses []*k8s.Ingress, secrets []*v1.Secret) (cache.Snapshot, error) {
c.Lock()
defer c.Unlock()

validIngresses := validIngressFilter(classFilter(ingresses, c.ingressClasses))
config := translateIngresses(validIngresses, c.syncSecrets, secrets, c.defaultTimeouts)
config := translateIngresses(validIngresses, c.syncSecrets, secrets, c.defaultTimeouts, c.accessLog)

vmatch, cmatch := config.equals(c.previousConfig)

Expand Down Expand Up @@ -212,7 +233,7 @@ func (c *KubernetesConfigurator) generateDynamicTLSFilterChains(config *envoyCon
Cert: virtualHost.TlsCert,
Key: virtualHost.TlsKey,
}
filterChain, err := c.makeFilterChain(certificate, []*route.VirtualHost{envoyVhost})
filterChain, err := c.makeFilterChain(certificate, []*route.VirtualHost{envoyVhost}, config.AccessLog)
if err != nil {
logrus.Warnf("error making filter chain: %v", err)
}
Expand All @@ -225,7 +246,7 @@ func (c *KubernetesConfigurator) generateDynamicTLSFilterChains(config *envoyCon
Cert: c.certificates[0].Cert,
Key: c.certificates[0].Key,
}
if defaultFC, err := c.makeFilterChain(defaultCert, allVhosts); err != nil {
if defaultFC, err := c.makeFilterChain(defaultCert, allVhosts, config.AccessLog); err != nil {
logrus.Warnf("error making default filter chain: %v", err)
} else {
filterChains = append(filterChains, &defaultFC)
Expand All @@ -245,7 +266,7 @@ func (c *KubernetesConfigurator) generateHTTPFilterChain(config *envoyConfigurat
virtualHosts = append(virtualHosts, vhost)
}

httpConnectionManager, err := c.makeConnectionManager(virtualHosts)
httpConnectionManager, err := c.makeConnectionManager(virtualHosts, config.AccessLog)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -291,7 +312,7 @@ func (c *KubernetesConfigurator) generateTLSFilterChains(config *envoyConfigurat
continue
}

filterChain, err := c.makeFilterChain(certificate, virtualHosts)
filterChain, err := c.makeFilterChain(certificate, virtualHosts, config.AccessLog)
if err != nil {
log.Printf("error making filter chain: %v", err)
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/envoy/configurator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestGenerate(t *testing.T) {

configurator := NewKubernetesConfigurator("a", []Certificate{
{Hosts: []string{"*"}, Cert: "b", Key: "c"},
}, "d", []string{"bar"})
}, "d", []string{"bar"}, "/var/log/envoy/")

snapshot, _ := configurator.Generate(ingresses, []*v1.Secret{})

Expand All @@ -73,7 +73,7 @@ func TestGenerateMultipleCerts(t *testing.T) {
configurator := NewKubernetesConfigurator("a", []Certificate{
{Hosts: []string{"*.internal.api.com"}, Cert: "com", Key: "com"},
{Hosts: []string{"*.internal.api.co.uk"}, Cert: "couk", Key: "couk"},
}, "d", []string{"bar"})
}, "d", []string{"bar"}, "/var/log/envoy/")

snapshot, err := configurator.Generate(ingresses, []*v1.Secret{})
if err != nil {
Expand All @@ -98,7 +98,7 @@ func TestGenerateMultipleHosts(t *testing.T) {

configurator := NewKubernetesConfigurator("a", []Certificate{
{Hosts: []string{"*.internal.api.com", "*.internal.api.co.uk"}, Cert: "com", Key: "com"},
}, "d", []string{"bar"})
}, "d", []string{"bar"}, "/var/log/envoy/")

snapshot, err := configurator.Generate(ingresses, []*v1.Secret{})
if err != nil {
Expand All @@ -123,7 +123,7 @@ func TestGenerateNoMatchingCert(t *testing.T) {

configurator := NewKubernetesConfigurator("a", []Certificate{
{Hosts: []string{"*.internal.api.com"}, Cert: "com", Key: "com"},
}, "d", []string{"bar"})
}, "d", []string{"bar"}, "/var/log/envoy/")

snapshot, err := configurator.Generate(ingresses, []*v1.Secret{})
if err != nil {
Expand All @@ -145,7 +145,7 @@ func TestGenerateIntoTwoCerts(t *testing.T) {
configurator := NewKubernetesConfigurator("a", []Certificate{
{Hosts: []string{"*.internal.api.com"}, Cert: "com", Key: "com"},
{Hosts: []string{"*"}, Cert: "all", Key: "all"},
}, "d", []string{"bar"})
}, "d", []string{"bar"}, "/var/log/envoy/")

snapshot, err := configurator.Generate(ingresses, []*v1.Secret{})
if err != nil {
Expand Down Expand Up @@ -218,7 +218,7 @@ func TestGenerateListeners(t *testing.T) {
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
configurator := NewKubernetesConfigurator("a", tc.certs, "", nil)
configurator := NewKubernetesConfigurator("a", tc.certs, "", nil, "/var/log/envoy/")
ret, err := configurator.generateListeners(&envoyConfiguration{VirtualHosts: tc.virtualHost})
if err != nil {
t.Fatalf("Error generating listeners %v", err)
Expand Down
4 changes: 3 additions & 1 deletion pkg/envoy/ingress_translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func VirtualHostsEquals(a, b []*virtualHost) bool {
type envoyConfiguration struct {
VirtualHosts []*virtualHost
Clusters []*cluster
AccessLog string
}

type virtualHost struct {
Expand Down Expand Up @@ -373,7 +374,7 @@ func validateSubdomain(ruleHost, host string) bool {
return strings.HasSuffix(host, ruleHost)
}

func translateIngresses(ingresses []*k8s.Ingress, syncSecrets bool, secrets []*v1.Secret, timeouts DefaultTimeouts) *envoyConfiguration {
func translateIngresses(ingresses []*k8s.Ingress, syncSecrets bool, secrets []*v1.Secret, timeouts DefaultTimeouts, accessLog string) *envoyConfiguration {
cfg := &envoyConfiguration{}
envoyIngresses := map[string]*envoyIngress{}

Expand Down Expand Up @@ -471,6 +472,7 @@ func translateIngresses(ingresses []*k8s.Ingress, syncSecrets bool, secrets []*v
for _, ingress := range envoyIngresses {
cfg.Clusters = append(cfg.Clusters, ingress.cluster)
cfg.VirtualHosts = append(cfg.VirtualHosts, ingress.vhost)
cfg.AccessLog = accessLog
}

numVhosts.Set(float64(len(cfg.VirtualHosts)))
Expand Down
18 changes: 9 additions & 9 deletions pkg/envoy/ingress_translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ func TestEquals(t *testing.T) {
Route: 15 * time.Second,
PerTry: 5 * time.Second,
}
c := translateIngresses([]*k8s.Ingress{ingress, ingress2}, false, []*v1.Secret{}, timeouts)
c2 := translateIngresses([]*k8s.Ingress{ingress, ingress2}, false, []*v1.Secret{}, timeouts)
c := translateIngresses([]*k8s.Ingress{ingress, ingress2}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")
c2 := translateIngresses([]*k8s.Ingress{ingress, ingress2}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")

vmatch, cmatch := c.equals(c2)
if vmatch != true {
Expand All @@ -231,8 +231,8 @@ func TestNotEquals(t *testing.T) {
Route: 15 * time.Second,
PerTry: 5 * time.Second,
}
c := translateIngresses([]*k8s.Ingress{ingress, ingress3, ingress2}, false, []*v1.Secret{}, timeouts)
c2 := translateIngresses([]*k8s.Ingress{ingress, ingress2, ingress4}, false, []*v1.Secret{}, timeouts)
c := translateIngresses([]*k8s.Ingress{ingress, ingress3, ingress2}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")
c2 := translateIngresses([]*k8s.Ingress{ingress, ingress2, ingress4}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")

vmatch, cmatch := c.equals(c2)
if vmatch == true {
Expand All @@ -252,8 +252,8 @@ func TestPartialEquals(t *testing.T) {
Route: 15 * time.Second,
PerTry: 5 * time.Second,
}
c := translateIngresses([]*k8s.Ingress{ingress2}, false, []*v1.Secret{}, timeouts)
c2 := translateIngresses([]*k8s.Ingress{ingress}, false, []*v1.Secret{}, timeouts)
c := translateIngresses([]*k8s.Ingress{ingress2}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")
c2 := translateIngresses([]*k8s.Ingress{ingress}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")

vmatch, cmatch := c2.equals(c)
if vmatch != true {
Expand All @@ -272,7 +272,7 @@ func TestGeneratesForSingleIngress(t *testing.T) {
Route: 15 * time.Second,
PerTry: 5 * time.Second,
}
c := translateIngresses([]*k8s.Ingress{ingress}, false, []*v1.Secret{}, timeouts)
c := translateIngresses([]*k8s.Ingress{ingress}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")

if len(c.VirtualHosts) != 1 {
t.Error("expected 1 virtual host")
Expand Down Expand Up @@ -313,7 +313,7 @@ func TestGeneratesForMultipleIngressSharingSpecHost(t *testing.T) {
Route: 15 * time.Second,
PerTry: 5 * time.Second,
}
c := translateIngresses([]*k8s.Ingress{fooIngress, barIngress}, false, []*v1.Secret{}, timeouts)
c := translateIngresses([]*k8s.Ingress{fooIngress, barIngress}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")

if len(c.VirtualHosts) != 1 {
t.Error("expected 1 virtual host")
Expand Down Expand Up @@ -373,7 +373,7 @@ func TestIngressWithIP(t *testing.T) {
Route: 15 * time.Second,
PerTry: 5 * time.Second,
}
c := translateIngresses([]*k8s.Ingress{ingress}, false, []*v1.Secret{}, timeouts)
c := translateIngresses([]*k8s.Ingress{ingress}, false, []*v1.Secret{}, timeouts, "/var/log/envoy/")
if c.Clusters[0].Hosts[0].Host != "127.0.0.1" {
t.Errorf("expected cluster host to be IP address, was %s", c.Clusters[0].Hosts[0])
}
Expand Down

0 comments on commit e7d67d6

Please sign in to comment.