From 885c832aed08487c58d73e5a7113d2f11c385bed Mon Sep 17 00:00:00 2001 From: "R.B. Boyer" Date: Mon, 19 Aug 2019 14:51:46 -0500 Subject: [PATCH] connect: ensure time.Duration fields retain their human readable forms in the API This applies for both config entries and the compiled discovery chain. Also omit some other config entries fields when empty. --- agent/structs/config_entry_discoverychain.go | 73 ++++++++++++++++++ agent/structs/discovery_chain.go | 37 +++++++++ api/config_entry.go | 12 +-- api/config_entry_discoverychain.go | 81 +++++++++++++++++++- api/discovery_chain.go | 37 +++++++++ 5 files changed, 231 insertions(+), 9 deletions(-) diff --git a/agent/structs/config_entry_discoverychain.go b/agent/structs/config_entry_discoverychain.go index 70a6e21db8c2..ee33d6bb5482 100644 --- a/agent/structs/config_entry_discoverychain.go +++ b/agent/structs/config_entry_discoverychain.go @@ -1,6 +1,7 @@ package structs import ( + "encoding/json" "fmt" "math" "regexp" @@ -317,6 +318,42 @@ type ServiceRouteDestination struct { RetryOnStatusCodes []uint32 `json:",omitempty"` } +func (e *ServiceRouteDestination) MarshalJSON() ([]byte, error) { + type Alias ServiceRouteDestination + exported := &struct { + RequestTimeout string `json:",omitempty"` + *Alias + }{ + RequestTimeout: e.RequestTimeout.String(), + Alias: (*Alias)(e), + } + if e.RequestTimeout == 0 { + exported.RequestTimeout = "" + } + + return json.Marshal(exported) +} + +func (e *ServiceRouteDestination) UnmarshalJSON(data []byte) error { + type Alias ServiceRouteDestination + aux := &struct { + RequestTimeout string + *Alias + }{ + Alias: (*Alias)(e), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.RequestTimeout != "" { + if e.RequestTimeout, err = time.ParseDuration(aux.RequestTimeout); err != nil { + return err + } + } + return nil +} + func (d *ServiceRouteDestination) HasRetryFeatures() bool { return d.NumRetries > 0 || d.RetryOnConnectFailure || len(d.RetryOnStatusCodes) > 0 } @@ -563,6 +600,42 @@ type ServiceResolverConfigEntry struct { RaftIndex } +func (e *ServiceResolverConfigEntry) MarshalJSON() ([]byte, error) { + type Alias ServiceResolverConfigEntry + exported := &struct { + ConnectTimeout string `json:",omitempty"` + *Alias + }{ + ConnectTimeout: e.ConnectTimeout.String(), + Alias: (*Alias)(e), + } + if e.ConnectTimeout == 0 { + exported.ConnectTimeout = "" + } + + return json.Marshal(exported) +} + +func (e *ServiceResolverConfigEntry) UnmarshalJSON(data []byte) error { + type Alias ServiceResolverConfigEntry + aux := &struct { + ConnectTimeout string + *Alias + }{ + Alias: (*Alias)(e), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.ConnectTimeout != "" { + if e.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil { + return err + } + } + return nil +} + func (e *ServiceResolverConfigEntry) SubsetExists(name string) bool { if name == "" { return true diff --git a/agent/structs/discovery_chain.go b/agent/structs/discovery_chain.go index 289539b85b4e..1b00aebcc884 100644 --- a/agent/structs/discovery_chain.go +++ b/agent/structs/discovery_chain.go @@ -1,6 +1,7 @@ package structs import ( + "encoding/json" "fmt" "time" ) @@ -130,6 +131,42 @@ type DiscoveryResolver struct { Failover *DiscoveryFailover `json:",omitempty"` } +func (r *DiscoveryResolver) MarshalJSON() ([]byte, error) { + type Alias DiscoveryResolver + exported := &struct { + ConnectTimeout string `json:",omitempty"` + *Alias + }{ + ConnectTimeout: r.ConnectTimeout.String(), + Alias: (*Alias)(r), + } + if r.ConnectTimeout == 0 { + exported.ConnectTimeout = "" + } + + return json.Marshal(exported) +} + +func (r *DiscoveryResolver) UnmarshalJSON(data []byte) error { + type Alias DiscoveryResolver + aux := &struct { + ConnectTimeout string + *Alias + }{ + Alias: (*Alias)(r), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.ConnectTimeout != "" { + if r.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil { + return err + } + } + return nil +} + // compiled form of ServiceRoute type DiscoveryRoute struct { Definition *ServiceRoute `json:",omitempty"` diff --git a/api/config_entry.go b/api/config_entry.go index 4348171a9c61..1588f2eed8ef 100644 --- a/api/config_entry.go +++ b/api/config_entry.go @@ -53,15 +53,15 @@ const ( // services type MeshGatewayConfig struct { // Mode is the mode that should be used for the upstream connection. - Mode MeshGatewayMode + Mode MeshGatewayMode `json:",omitempty"` } type ServiceConfigEntry struct { Kind string Name string - Protocol string - MeshGateway MeshGatewayConfig - ExternalSNI string + Protocol string `json:",omitempty"` + MeshGateway MeshGatewayConfig `json:",omitempty"` + ExternalSNI string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } @@ -85,8 +85,8 @@ func (s *ServiceConfigEntry) GetModifyIndex() uint64 { type ProxyConfigEntry struct { Kind string Name string - Config map[string]interface{} - MeshGateway MeshGatewayConfig + Config map[string]interface{} `json:",omitempty"` + MeshGateway MeshGatewayConfig `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } diff --git a/api/config_entry_discoverychain.go b/api/config_entry_discoverychain.go index e0d3e9b1bee6..77acfbddf1ea 100644 --- a/api/config_entry_discoverychain.go +++ b/api/config_entry_discoverychain.go @@ -1,12 +1,15 @@ package api -import "time" +import ( + "encoding/json" + "time" +) type ServiceRouterConfigEntry struct { Kind string Name string - Routes []ServiceRoute + Routes []ServiceRoute `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 @@ -64,11 +67,47 @@ type ServiceRouteDestination struct { RetryOnStatusCodes []uint32 `json:",omitempty"` } +func (e *ServiceRouteDestination) MarshalJSON() ([]byte, error) { + type Alias ServiceRouteDestination + exported := &struct { + RequestTimeout string `json:",omitempty"` + *Alias + }{ + RequestTimeout: e.RequestTimeout.String(), + Alias: (*Alias)(e), + } + if e.RequestTimeout == 0 { + exported.RequestTimeout = "" + } + + return json.Marshal(exported) +} + +func (e *ServiceRouteDestination) UnmarshalJSON(data []byte) error { + type Alias ServiceRouteDestination + aux := &struct { + RequestTimeout string + *Alias + }{ + Alias: (*Alias)(e), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.RequestTimeout != "" { + if e.RequestTimeout, err = time.ParseDuration(aux.RequestTimeout); err != nil { + return err + } + } + return nil +} + type ServiceSplitterConfigEntry struct { Kind string Name string - Splits []ServiceSplit + Splits []ServiceSplit `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 @@ -100,6 +139,42 @@ type ServiceResolverConfigEntry struct { ModifyIndex uint64 } +func (e *ServiceResolverConfigEntry) MarshalJSON() ([]byte, error) { + type Alias ServiceResolverConfigEntry + exported := &struct { + ConnectTimeout string `json:",omitempty"` + *Alias + }{ + ConnectTimeout: e.ConnectTimeout.String(), + Alias: (*Alias)(e), + } + if e.ConnectTimeout == 0 { + exported.ConnectTimeout = "" + } + + return json.Marshal(exported) +} + +func (e *ServiceResolverConfigEntry) UnmarshalJSON(data []byte) error { + type Alias ServiceResolverConfigEntry + aux := &struct { + ConnectTimeout string + *Alias + }{ + Alias: (*Alias)(e), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.ConnectTimeout != "" { + if e.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil { + return err + } + } + return nil +} + func (e *ServiceResolverConfigEntry) GetKind() string { return e.Kind } func (e *ServiceResolverConfigEntry) GetName() string { return e.Name } func (e *ServiceResolverConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex } diff --git a/api/discovery_chain.go b/api/discovery_chain.go index 4d7b112c84bd..407a3b08e37d 100644 --- a/api/discovery_chain.go +++ b/api/discovery_chain.go @@ -1,6 +1,7 @@ package api import ( + "encoding/json" "fmt" "time" ) @@ -169,6 +170,42 @@ type DiscoveryResolver struct { Failover *DiscoveryFailover } +func (r *DiscoveryResolver) MarshalJSON() ([]byte, error) { + type Alias DiscoveryResolver + exported := &struct { + ConnectTimeout string `json:",omitempty"` + *Alias + }{ + ConnectTimeout: r.ConnectTimeout.String(), + Alias: (*Alias)(r), + } + if r.ConnectTimeout == 0 { + exported.ConnectTimeout = "" + } + + return json.Marshal(exported) +} + +func (r *DiscoveryResolver) UnmarshalJSON(data []byte) error { + type Alias DiscoveryResolver + aux := &struct { + ConnectTimeout string + *Alias + }{ + Alias: (*Alias)(r), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.ConnectTimeout != "" { + if r.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil { + return err + } + } + return nil +} + // compiled form of ServiceResolverFailover type DiscoveryFailover struct { Targets []string