From fd1c62ee8bd7ec054d5f48639d633317648c8d02 Mon Sep 17 00:00:00 2001 From: "R.B. Boyer" Date: Mon, 19 Aug 2019 15:31:05 -0500 Subject: [PATCH] connect: ensure time.Duration fields retain their human readable forms in the API (#6348) 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