Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for host pass in upstream crd #1889

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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