Skip to content

Commit

Permalink
feat: add support for host pass in upstream crd (apache#1889)
Browse files Browse the repository at this point in the history
Co-authored-by: Katlinsky, Ilya <[email protected]>
  • Loading branch information
ikatlinsky and ikatlinski authored Aug 26, 2023
1 parent 14e3c61 commit 7b3deb5
Show file tree
Hide file tree
Showing 7 changed files with 292 additions and 35 deletions.
2 changes: 2 additions & 0 deletions docs/en/latest/references/apisix_upstream.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,5 @@ See the [definition](https://github.com/apache/apisix-ingress-controller/blob/ma
| discovery.serviceName | string | Name of the upstream service. |
| discovery.type | string | Types of Service Discovery, which indicates what registry in APISIX the discovery uses. Should match the entry in APISIX's config. Can refer to the [doc](https://apisix.apache.org/docs/apisix/discovery/) |
| discovery.args | object | Args map for discovery-spcefic parameters. Also can refer to the [doc](https://apisix.apache.org/docs/apisix/discovery/) |
| passHost | string | Configures the host when the request is forwarded to the upstream. Can be one of pass, node or rewrite. Defaults to pass if not specified: pass - transparently passes the client's host to the Upstream, node - uses the host configured in the node of the Upstream, rewrite - uses the value configured in upstreamHost.
| upstreamHost | string | Specifies the host of the Upstream request. This is only valid if the passHost is set to rewrite.
10 changes: 10 additions & 0 deletions pkg/kube/apisix/apis/config/v2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,16 @@ type ApisixUpstreamConfig struct {
// +optional
Subsets []ApisixUpstreamSubset `json:"subsets,omitempty" yaml:"subsets,omitempty"`

// Configures the host when the request is forwarded to the upstream.
// Can be one of pass, node or rewrite.
// +optional
PassHost string `json:"passHost,omitempty" yaml:"passHost,omitempty"`

// Specifies the host of the Upstream request. This is only valid if
// the pass_host is set to rewrite
// +optional
UpstreamHost string `json:"upstreamHost,omitempty" yaml:"upstreamHost,omitempty"`

// Discovery is used to configure service discovery for upstream.
// +optional
Discovery *Discovery `json:"discovery,omitempty" yaml:"discovery,omitempty"`
Expand Down
21 changes: 21 additions & 0 deletions pkg/providers/translation/apisix_upstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import (
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)

type passHostConfig struct {
passHost string
upstreamHost string
}

func (t *translator) TranslateUpstreamConfigV2(au *configv2.ApisixUpstreamConfig) (*apisixv1.Upstream, error) {
ups := apisixv1.NewDefaultUpstream()
if err := t.translateUpstreamScheme(au.Scheme, ups); err != nil {
Expand All @@ -38,6 +43,9 @@ func (t *translator) TranslateUpstreamConfigV2(au *configv2.ApisixUpstreamConfig
if err := t.translateClientTLSV2(au.TLSSecret, ups); err != nil {
return nil, err
}
if err := t.translatePassHost(&passHostConfig{au.PassHost, au.UpstreamHost}, ups); err != nil {
return nil, err
}
if err := t.translateUpstreamDiscovery(au.Discovery, ups); err != nil {
return nil, err
}
Expand Down Expand Up @@ -368,3 +376,16 @@ func (t *translator) translateUpstreamPassiveHealthCheckV2(config *configv2.Pass
}
return &passive, nil
}

func (t *translator) translatePassHost(ph *passHostConfig, ups *apisixv1.Upstream) error {
switch ph.passHost {
case "", apisixv1.PassHostPass, apisixv1.PassHostNode, apisixv1.PassHostRewrite:
ups.PassHost = ph.passHost
default:
return &TranslateError{Field: "passHost", Reason: "invalid value"}
}

ups.UpstreamHost = ph.upstreamHost

return nil
}
47 changes: 47 additions & 0 deletions pkg/providers/translation/apisix_upstream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,50 @@ func TestUpstreamRetriesAndTimeoutV2(t *testing.T) {
Read: 15,
}, ups.Timeout)
}

func TestUpstreamPassHost(t *testing.T) {
tr := &translator{}
tests := []struct {
name string
phc *passHostConfig
wantFunc func(t *testing.T, err error, ups *apisixv1.Upstream, phc *passHostConfig)
}{
{
name: "should be empty when settings not set explicitly",
phc: &passHostConfig{},
wantFunc: func(t *testing.T, err error, ups *apisixv1.Upstream, phc *passHostConfig) {
assert.Nil(t, err)
assert.Empty(t, ups.PassHost)
assert.Empty(t, ups.UpstreamHost)
},
},
{
name: "should set passHost to pass",
phc: &passHostConfig{passHost: apisixv1.PassHostPass},
wantFunc: func(t *testing.T, err error, ups *apisixv1.Upstream, phc *passHostConfig) {
assert.Nil(t, err)
assert.Equal(t, phc.passHost, ups.PassHost)
assert.Empty(t, ups.UpstreamHost)
},
},
{
name: "should fail when passHost set to invalid value",
phc: &passHostConfig{passHost: "unknown"},
wantFunc: func(t *testing.T, err error, ups *apisixv1.Upstream, phc *passHostConfig) {
assert.Equal(t, &TranslateError{
Field: "passHost",
Reason: "invalid value",
}, err)
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ups := apisixv1.NewDefaultUpstream()
err := tr.translatePassHost(tt.phc, ups)

tt.wantFunc(t, err, ups, tt.phc)
})
}
}
87 changes: 52 additions & 35 deletions pkg/types/apisix/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ const (
// DefaultUpstreamTimeout represents the default connect,
// read and send timeout (in seconds) with upstreams.
DefaultUpstreamTimeout = 60

// PassHostPass represents pass option for pass_host Upstream settings.
PassHostPass = "pass"
// PassHostPass represents node option for pass_host Upstream settings.
PassHostNode = "node"
// PassHostPass represents rewrite option for pass_host Upstream settings.
PassHostRewrite = "rewrite"
)

var ValidSchemes map[string]struct{} = map[string]struct{}{
Expand Down Expand Up @@ -196,15 +203,17 @@ func (p *Plugins) DeepCopy() *Plugins {
type Upstream struct {
Metadata `json:",inline" yaml:",inline"`

Type string `json:"type,omitempty" yaml:"type,omitempty"`
HashOn string `json:"hash_on,omitempty" yaml:"hash_on,omitempty"`
Key string `json:"key,omitempty" yaml:"key,omitempty"`
Checks *UpstreamHealthCheck `json:"checks,omitempty" yaml:"checks,omitempty"`
Nodes UpstreamNodes `json:"nodes" yaml:"nodes"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"`
Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
HashOn string `json:"hash_on,omitempty" yaml:"hash_on,omitempty"`
Key string `json:"key,omitempty" yaml:"key,omitempty"`
Checks *UpstreamHealthCheck `json:"checks,omitempty" yaml:"checks,omitempty"`
Nodes UpstreamNodes `json:"nodes" yaml:"nodes"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"`
Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
PassHost string `json:"pass_host,omitempty" yaml:"pass_host,omitempty"`
UpstreamHost string `json:"upstream_host,omitempty" yaml:"upstream_host,omitempty"`

// for Service Discovery
ServiceName string `json:"service_name,omitempty" yaml:"service_name,omitempty"`
Expand Down Expand Up @@ -271,10 +280,12 @@ func (up Upstream) MarshalJSON() ([]byte, error) {
Key string `json:"key,omitempty" yaml:"key,omitempty"`
Checks *UpstreamHealthCheck `json:"checks,omitempty" yaml:"checks,omitempty"`
//Nodes UpstreamNodes `json:"nodes" yaml:"nodes"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"`
Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"`
Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"`
HostPass string `json:"pass_host,omitempty" yaml:"pass_host,omitempty"`
UpstreamHost string `json:"upstream_host,omitempty" yaml:"upstream_host,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" yaml:"tls,omitempty"`

// for Service Discovery
ServiceName string `json:"service_name,omitempty" yaml:"service_name,omitempty"`
Expand All @@ -288,10 +299,12 @@ func (up Upstream) MarshalJSON() ([]byte, error) {
Key: up.Key,
Checks: up.Checks,
//Nodes: up.Nodes,
Scheme: up.Scheme,
Retries: up.Retries,
Timeout: up.Timeout,
TLS: up.TLS,
Scheme: up.Scheme,
Retries: up.Retries,
Timeout: up.Timeout,
HostPass: up.PassHost,
UpstreamHost: up.UpstreamHost,
TLS: up.TLS,

ServiceName: up.ServiceName,
DiscoveryType: up.DiscoveryType,
Expand All @@ -301,15 +314,17 @@ func (up Upstream) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Metadata `json:",inline" yaml:",inline"`

Type string `json:"type,omitempty" yaml:"type,omitempty"`
HashOn string `json:"hash_on,omitempty" yaml:"hash_on,omitempty"`
Key string `json:"key,omitempty" yaml:"key,omitempty"`
Checks *UpstreamHealthCheck `json:"checks,omitempty" yaml:"checks,omitempty"`
Nodes UpstreamNodes `json:"nodes" yaml:"nodes"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"`
Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
HashOn string `json:"hash_on,omitempty" yaml:"hash_on,omitempty"`
Key string `json:"key,omitempty" yaml:"key,omitempty"`
Checks *UpstreamHealthCheck `json:"checks,omitempty" yaml:"checks,omitempty"`
Nodes UpstreamNodes `json:"nodes" yaml:"nodes"`
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"`
Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"`
HostPass string `json:"pass_host,omitempty" yaml:"pass_host,omitempty"`
UpstreamHost string `json:"upstream_host,omitempty" yaml:"upstream_host,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" yaml:"tls,omitempty"`

// for Service Discovery
//ServiceName string `json:"service_name,omitempty" yaml:"service_name,omitempty"`
Expand All @@ -318,15 +333,17 @@ func (up Upstream) MarshalJSON() ([]byte, error) {
}{
Metadata: up.Metadata,

Type: up.Type,
HashOn: up.HashOn,
Key: up.Key,
Checks: up.Checks,
Nodes: up.Nodes,
Scheme: up.Scheme,
Retries: up.Retries,
Timeout: up.Timeout,
TLS: up.TLS,
Type: up.Type,
HashOn: up.HashOn,
Key: up.Key,
Checks: up.Checks,
Nodes: up.Nodes,
Scheme: up.Scheme,
Retries: up.Retries,
Timeout: up.Timeout,
HostPass: up.PassHost,
UpstreamHost: up.UpstreamHost,
TLS: up.TLS,

//ServiceName: up.ServiceName,
//DiscoveryType: up.DiscoveryType,
Expand Down
9 changes: 9 additions & 0 deletions samples/deploy/crd/v1/ApisixUpstream.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,15 @@ spec:
type: string
send:
type: string
passHost:
type: string
enum:
- pass
- node
- rewrite
upstreamHost:
type: string
pattern: "^\\*?[0-9a-zA-Z-._]+$"
tlsSecret:
description: ApisixSecret describes the Kubernetes Secret name and
namespace.
Expand Down
Loading

0 comments on commit 7b3deb5

Please sign in to comment.