| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package translation |
| |
| import ( |
| configv1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v1" |
| apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" |
| ) |
| |
| func (t *translator) translateUpstreamRetriesAndTimeout(retries int, timeout *configv1.UpstreamTimeout, ups *apisixv1.Upstream) error { |
| if retries < 0 { |
| return &translateError{ |
| field: "retries", |
| reason: "invalid value", |
| } |
| } |
| ups.Retries = retries |
| if timeout == nil { |
| return nil |
| } |
| |
| // Since the schema of timeout doesn't allow only configuring |
| // one or two items. Here we assign the default value first. |
| connTimeout := apisixv1.DefaultUpstreamTimeout |
| readTimeout := apisixv1.DefaultUpstreamTimeout |
| sendTimeout := apisixv1.DefaultUpstreamTimeout |
| if timeout.Connect.Duration < 0 { |
| return &translateError{ |
| field: "timeout.connect", |
| reason: "invalid value", |
| } |
| } else if timeout.Connect.Duration > 0 { |
| connTimeout = int(timeout.Connect.Seconds()) |
| } |
| if timeout.Read.Duration < 0 { |
| return &translateError{ |
| field: "timeout.read", |
| reason: "invalid value", |
| } |
| } else if timeout.Read.Duration > 0 { |
| readTimeout = int(timeout.Read.Seconds()) |
| } |
| if timeout.Send.Duration < 0 { |
| return &translateError{ |
| field: "timeout.send", |
| reason: "invalid value", |
| } |
| } else if timeout.Send.Duration > 0 { |
| sendTimeout = int(timeout.Send.Seconds()) |
| } |
| ups.Timeout = &apisixv1.UpstreamTimeout{ |
| Connect: connTimeout, |
| Send: sendTimeout, |
| Read: readTimeout, |
| } |
| return nil |
| } |
| |
| func (t *translator) translateUpstreamScheme(scheme string, ups *apisixv1.Upstream) error { |
| if scheme == "" { |
| ups.Scheme = apisixv1.SchemeHTTP |
| return nil |
| } |
| switch scheme { |
| case apisixv1.SchemeHTTP, apisixv1.SchemeGRPC: |
| ups.Scheme = scheme |
| return nil |
| default: |
| return &translateError{field: "scheme", reason: "invalid value"} |
| } |
| } |
| |
| func (t *translator) translateUpstreamLoadBalancer(lb *configv1.LoadBalancer, ups *apisixv1.Upstream) error { |
| if lb == nil || lb.Type == "" { |
| ups.Type = apisixv1.LbRoundRobin |
| return nil |
| } |
| switch lb.Type { |
| case apisixv1.LbRoundRobin, apisixv1.LbLeastConn, apisixv1.LbEwma: |
| ups.Type = lb.Type |
| case apisixv1.LbConsistentHash: |
| ups.Type = lb.Type |
| ups.Key = lb.Key |
| switch lb.HashOn { |
| case apisixv1.HashOnVars: |
| fallthrough |
| case apisixv1.HashOnHeader: |
| fallthrough |
| case apisixv1.HashOnCookie: |
| fallthrough |
| case apisixv1.HashOnConsumer: |
| fallthrough |
| case apisixv1.HashOnVarsCombination: |
| ups.HashOn = lb.HashOn |
| default: |
| return &translateError{field: "loadbalancer.hashOn", reason: "invalid value"} |
| } |
| default: |
| return &translateError{ |
| field: "loadbalancer.type", |
| reason: "invalid value", |
| } |
| } |
| return nil |
| } |
| |
| func (t *translator) translateUpstreamHealthCheck(config *configv1.HealthCheck, ups *apisixv1.Upstream) error { |
| if config == nil || (config.Passive == nil && config.Active == nil) { |
| return nil |
| } |
| var hc apisixv1.UpstreamHealthCheck |
| if config.Passive != nil { |
| passive, err := t.translateUpstreamPassiveHealthCheck(config.Passive) |
| if err != nil { |
| return err |
| } |
| hc.Passive = passive |
| } |
| |
| if config.Active != nil { |
| active, err := t.translateUpstreamActiveHealthCheck(config.Active) |
| if err != nil { |
| return err |
| } |
| hc.Active = active |
| } else { |
| return &translateError{ |
| field: "healthCheck.active", |
| reason: "not exist", |
| } |
| } |
| |
| ups.Checks = &hc |
| return nil |
| } |
| |
| func (t *translator) translateUpstreamActiveHealthCheck(config *configv1.ActiveHealthCheck) (*apisixv1.UpstreamActiveHealthCheck, error) { |
| var active apisixv1.UpstreamActiveHealthCheck |
| switch config.Type { |
| case apisixv1.HealthCheckHTTP, apisixv1.HealthCheckHTTPS, apisixv1.HealthCheckTCP: |
| active.Type = config.Type |
| case "": |
| active.Type = apisixv1.HealthCheckHTTP |
| default: |
| return nil, &translateError{ |
| field: "healthCheck.active.Type", |
| reason: "invalid value", |
| } |
| } |
| |
| active.Timeout = int(config.Timeout.Seconds()) |
| if config.Port < 0 || config.Port > 65535 { |
| return nil, &translateError{ |
| field: "healthCheck.active.port", |
| reason: "invalid value", |
| } |
| } else { |
| active.Port = config.Port |
| } |
| if config.Concurrency < 0 { |
| return nil, &translateError{ |
| field: "healthCheck.active.concurrency", |
| reason: "invalid value", |
| } |
| } else { |
| active.Concurrency = config.Concurrency |
| } |
| active.Host = config.Host |
| active.HTTPPath = config.HTTPPath |
| active.HTTPRequestHeaders = config.RequestHeaders |
| |
| if config.StrictTLS == nil || *config.StrictTLS { |
| active.HTTPSVerifyCert = true |
| } |
| |
| if config.Healthy != nil { |
| if config.Healthy.Successes < 0 || config.Healthy.Successes > apisixv1.HealthCheckMaxConsecutiveNumber { |
| return nil, &translateError{ |
| field: "healthCheck.active.healthy.successes", |
| reason: "invalid value", |
| } |
| } |
| active.Healthy.Successes = config.Healthy.Successes |
| if config.Healthy.HTTPCodes != nil && len(config.Healthy.HTTPCodes) < 1 { |
| return nil, &translateError{ |
| field: "healthCheck.active.healthy.httpCodes", |
| reason: "empty", |
| } |
| } |
| active.Healthy.HTTPStatuses = config.Healthy.HTTPCodes |
| |
| if config.Healthy.Interval.Duration < apisixv1.ActiveHealthCheckMinInterval { |
| return nil, &translateError{ |
| field: "healthCheck.active.healthy.interval", |
| reason: "invalid value", |
| } |
| } |
| active.Healthy.Interval = int(config.Healthy.Interval.Seconds()) |
| } |
| |
| if config.Unhealthy != nil { |
| if config.Unhealthy.HTTPFailures < 0 || config.Unhealthy.HTTPFailures > apisixv1.HealthCheckMaxConsecutiveNumber { |
| return nil, &translateError{ |
| field: "healthCheck.active.unhealthy.httpFailures", |
| reason: "invalid value", |
| } |
| } |
| active.Unhealthy.HTTPFailures = config.Unhealthy.HTTPFailures |
| |
| if config.Unhealthy.TCPFailures < 0 || config.Unhealthy.TCPFailures > apisixv1.HealthCheckMaxConsecutiveNumber { |
| return nil, &translateError{ |
| field: "healthCheck.active.unhealthy.tcpFailures", |
| reason: "invalid value", |
| } |
| } |
| active.Unhealthy.TCPFailures = config.Unhealthy.TCPFailures |
| active.Unhealthy.Timeouts = config.Unhealthy.Timeout.Seconds() |
| |
| if config.Unhealthy.HTTPCodes != nil && len(config.Unhealthy.HTTPCodes) < 1 { |
| return nil, &translateError{ |
| field: "healthCheck.active.unhealthy.httpCodes", |
| reason: "empty", |
| } |
| } |
| active.Unhealthy.HTTPStatuses = config.Unhealthy.HTTPCodes |
| |
| if config.Unhealthy.Interval.Duration < apisixv1.ActiveHealthCheckMinInterval { |
| return nil, &translateError{ |
| field: "healthCheck.active.unhealthy.interval", |
| reason: "invalid value", |
| } |
| } |
| active.Unhealthy.Interval = int(config.Unhealthy.Interval.Seconds()) |
| } |
| |
| return &active, nil |
| } |
| |
| func (t *translator) translateUpstreamPassiveHealthCheck(config *configv1.PassiveHealthCheck) (*apisixv1.UpstreamPassiveHealthCheck, error) { |
| var passive apisixv1.UpstreamPassiveHealthCheck |
| switch config.Type { |
| case apisixv1.HealthCheckHTTP, apisixv1.HealthCheckHTTPS, apisixv1.HealthCheckTCP: |
| passive.Type = config.Type |
| case "": |
| passive.Type = apisixv1.HealthCheckHTTP |
| default: |
| return nil, &translateError{ |
| field: "healthCheck.passive.Type", |
| reason: "invalid value", |
| } |
| } |
| if config.Healthy != nil { |
| // zero means use the default value. |
| if config.Healthy.Successes < 0 || config.Healthy.Successes > apisixv1.HealthCheckMaxConsecutiveNumber { |
| return nil, &translateError{ |
| field: "healthCheck.passive.healthy.successes", |
| reason: "invalid value", |
| } |
| } |
| passive.Healthy.Successes = config.Healthy.Successes |
| if config.Healthy.HTTPCodes != nil && len(config.Healthy.HTTPCodes) < 1 { |
| return nil, &translateError{ |
| field: "healthCheck.passive.healthy.httpCodes", |
| reason: "empty", |
| } |
| } |
| passive.Healthy.HTTPStatuses = config.Healthy.HTTPCodes |
| } |
| |
| if config.Unhealthy != nil { |
| if config.Unhealthy.HTTPFailures < 0 || config.Unhealthy.HTTPFailures > apisixv1.HealthCheckMaxConsecutiveNumber { |
| return nil, &translateError{ |
| field: "healthCheck.passive.unhealthy.httpFailures", |
| reason: "invalid value", |
| } |
| } |
| passive.Unhealthy.HTTPFailures = config.Unhealthy.HTTPFailures |
| |
| if config.Unhealthy.TCPFailures < 0 || config.Unhealthy.TCPFailures > apisixv1.HealthCheckMaxConsecutiveNumber { |
| return nil, &translateError{ |
| field: "healthCheck.passive.unhealthy.tcpFailures", |
| reason: "invalid value", |
| } |
| } |
| passive.Unhealthy.TCPFailures = config.Unhealthy.TCPFailures |
| passive.Unhealthy.Timeouts = config.Unhealthy.Timeout.Seconds() |
| |
| if config.Unhealthy.HTTPCodes != nil && len(config.Unhealthy.HTTPCodes) < 1 { |
| return nil, &translateError{ |
| field: "healthCheck.passive.unhealthy.httpCodes", |
| reason: "empty", |
| } |
| } |
| passive.Unhealthy.HTTPStatuses = config.Unhealthy.HTTPCodes |
| } |
| return &passive, nil |
| } |