diff --git a/pkg/apis/apisix/v2/register.go b/pkg/apis/apisix/v2/register.go index 04b086e..4ce78b1 100644 --- a/pkg/apis/apisix/v2/register.go +++ b/pkg/apis/apisix/v2/register.go @@ -46,6 +46,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &ApisixRoute{}, &ApisixRouteList{}, + &ApisixUpstream{}, + &ApisixUpstreamList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/apisix/v2/types.go b/pkg/apis/apisix/v2/types.go index cbd33e2..1de3cd2 100644 --- a/pkg/apis/apisix/v2/types.go +++ b/pkg/apis/apisix/v2/types.go @@ -18,6 +18,7 @@ package v2 import ( "encoding/json" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -243,3 +244,194 @@ type ApisixRouteList struct { metav1.ListMeta `json:"metadata" yaml:"metadata"` Items []ApisixRoute `json:"items,omitempty" yaml:"items,omitempty"` } + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:subresource:status +// ApisixUpstream is a decorator for Kubernetes Service, it arms the Service +// with rich features like health check, retry policies, load balancer and others. +// It's designed to have same name with the Kubernetes Service and can be customized +// for individual port. +type ApisixUpstream struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` + + Spec *ApisixUpstreamSpec `json:"spec,omitempty" yaml:"spec,omitempty"` + Status ApisixStatus `json:"status,omitempty" yaml:"status,omitempty"` +} + +// ApisixUpstreamSpec describes the specification of ApisixUpstream. +type ApisixUpstreamSpec struct { + // ExternalNodes contains external nodes the Upstream should use + // If this field is set, the upstream will use these nodes directly without any further resolves + // +optional + ExternalNodes []ApisixUpstreamExternalNode `json:"externalNodes,omitempty" yaml:"externalNodes,omitempty"` + + ApisixUpstreamConfig `json:",inline" yaml:",inline"` + + PortLevelSettings []PortLevelSettings `json:"portLevelSettings,omitempty" yaml:"portLevelSettings,omitempty"` +} + +// ApisixUpstreamConfig contains rich features on APISIX Upstream, for instance +// load balancer, health check, etc. +type ApisixUpstreamConfig struct { + // LoadBalancer represents the load balancer configuration for Kubernetes Service. + // The default strategy is round robin. + // +optional + LoadBalancer *LoadBalancer `json:"loadbalancer,omitempty" yaml:"loadbalancer,omitempty"` + // The scheme used to talk with the upstream. + // Now value can be http, grpc. + // +optional + Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"` + + // How many times that the proxy (Apache APISIX) should do when + // errors occur (error, timeout or bad http status codes like 500, 502). + // +optional + Retries *int `json:"retries,omitempty" yaml:"retries,omitempty"` + + // Timeout settings for the read, send and connect to the upstream. + // +optional + Timeout *UpstreamTimeout `json:"timeout,omitempty" yaml:"timeout,omitempty"` + + // The health check configurations for the upstream. + // +optional + HealthCheck *HealthCheck `json:"healthCheck,omitempty" yaml:"healthCheck,omitempty"` + + // Set the client certificate when connecting to TLS upstream. + // +optional + TLSSecret *ApisixSecret `json:"tlsSecret,omitempty" yaml:"tlsSecret,omitempty"` + + // Subsets groups the service endpoints by their labels. Usually used to differentiate + // service versions. + // +optional + Subsets []ApisixUpstreamSubset `json:"subsets,omitempty" yaml:"subsets,omitempty"` +} + +// ApisixUpstreamExternalType is the external service type +type ApisixUpstreamExternalType string + +const ( + // ExternalTypeDomain type is a domain + // +k8s:deepcopy-gen=false + ExternalTypeDomain ApisixUpstreamExternalType = "Domain" + + // ExternalTypeService type is a K8s ExternalName service + // +k8s:deepcopy-gen=false + ExternalTypeService ApisixUpstreamExternalType = "Service" +) + +// ApisixUpstreamExternalNode is the external node conf +type ApisixUpstreamExternalNode struct { + Name string `json:"name,omitempty" yaml:"name"` + Type ApisixUpstreamExternalType `json:"type,omitempty" yaml:"type"` + // +optional + Weight *int `json:"weight,omitempty" yaml:"weight"` + // Port defines the port of the external node + // +optional + Port *int `json:"port,omitempty" yaml:"port"` +} + +// ApisixUpstreamSubset defines a single endpoints group of one Service. +type ApisixUpstreamSubset struct { + // Name is the name of subset. + Name string `json:"name" yaml:"name"` + // Labels is the label set of this subset. + Labels map[string]string `json:"labels" yaml:"labels"` +} + +// PortLevelSettings configures the ApisixUpstreamConfig for each individual port. It inherits +// configurations from the outer level (the whole Kubernetes Service) and overrides some of +// them if they are set on the port level. +type PortLevelSettings struct { + ApisixUpstreamConfig `json:",inline" yaml:",inline"` + + // Port is a Kubernetes Service port, it should be already defined. + Port int32 `json:"port" yaml:"port"` +} + +// LoadBalancer describes the load balancing parameters. +type LoadBalancer struct { + Type string `json:"type" yaml:"type"` + // The HashOn and Key fields are required when Type is "chash". + // HashOn represents the key fetching scope. + HashOn string `json:"hashOn,omitempty" yaml:"hashOn,omitempty"` + // Key represents the hash key. + Key string `json:"key,omitempty" yaml:"key,omitempty"` +} + +// HealthCheck describes the upstream health check parameters. +type HealthCheck struct { + Active *ActiveHealthCheck `json:"active" yaml:"active"` + Passive *PassiveHealthCheck `json:"passive,omitempty" yaml:"passive,omitempty"` +} + +// ActiveHealthCheck defines the active kind of upstream health check. +type ActiveHealthCheck struct { + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Timeout time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"` + Concurrency int `json:"concurrency,omitempty" yaml:"concurrency,omitempty"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + Port int32 `json:"port,omitempty" yaml:"port,omitempty"` + HTTPPath string `json:"httpPath,omitempty" yaml:"httpPath,omitempty"` + StrictTLS *bool `json:"strictTLS,omitempty" yaml:"strictTLS,omitempty"` + RequestHeaders []string `json:"requestHeaders,omitempty" yaml:"requestHeaders,omitempty"` + Healthy *ActiveHealthCheckHealthy `json:"healthy,omitempty" yaml:"healthy,omitempty"` + Unhealthy *ActiveHealthCheckUnhealthy `json:"unhealthy,omitempty" yaml:"unhealthy,omitempty"` +} + +// PassiveHealthCheck defines the conditions to judge whether +// an upstream node is healthy with the passive manager. +type PassiveHealthCheck struct { + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Healthy *PassiveHealthCheckHealthy `json:"healthy,omitempty" yaml:"healthy,omitempty"` + Unhealthy *PassiveHealthCheckUnhealthy `json:"unhealthy,omitempty" yaml:"unhealthy,omitempty"` +} + +// ActiveHealthCheckHealthy defines the conditions to judge whether +// an upstream node is healthy with the active manner. +type ActiveHealthCheckHealthy struct { + PassiveHealthCheckHealthy `json:",inline" yaml:",inline"` + + Interval metav1.Duration `json:"interval,omitempty" yaml:"interval,omitempty"` +} + +// ActiveHealthCheckUnhealthy defines the conditions to judge whether +// an upstream node is unhealthy with the active manager. +type ActiveHealthCheckUnhealthy struct { + PassiveHealthCheckUnhealthy `json:",inline" yaml:",inline"` + + Interval metav1.Duration `json:"interval,omitempty" yaml:"interval,omitempty"` +} + +// PassiveHealthCheckHealthy defines the conditions to judge whether +// an upstream node is healthy with the passive manner. +type PassiveHealthCheckHealthy struct { + HTTPCodes []int `json:"httpCodes,omitempty" yaml:"httpCodes,omitempty"` + Successes int `json:"successes,omitempty" yaml:"successes,omitempty"` +} + +// PassiveHealthCheckUnhealthy defines the conditions to judge whether +// an upstream node is unhealthy with the passive manager. +type PassiveHealthCheckUnhealthy struct { + HTTPCodes []int `json:"httpCodes,omitempty" yaml:"httpCodes,omitempty"` + HTTPFailures int `json:"httpFailures,omitempty" yaml:"http_failures,omitempty"` + TCPFailures int `json:"tcpFailures,omitempty" yaml:"tcpFailures,omitempty"` + Timeouts int `json:"timeout,omitempty" yaml:"timeout,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ApisixUpstreamList struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ListMeta `json:"metadata" yaml:"metadata"` + Items []ApisixUpstream `json:"items,omitempty" yaml:"items,omitempty"` +} + +// ApisixSecret describes the Kubernetes Secret name and namespace. +type ApisixSecret struct { + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Required + Name string `json:"name" yaml:"name"` + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Required + Namespace string `json:"namespace" yaml:"namespace"` +} diff --git a/pkg/apis/apisix/v2/zz_generated.deepcopy.go b/pkg/apis/apisix/v2/zz_generated.deepcopy.go index 90e5e23..caeca21 100644 --- a/pkg/apis/apisix/v2/zz_generated.deepcopy.go +++ b/pkg/apis/apisix/v2/zz_generated.deepcopy.go @@ -432,3 +432,413 @@ func (in *UpstreamTimeout) DeepCopy() *UpstreamTimeout { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstream) DeepCopyInto(out *ApisixUpstream) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(ApisixUpstreamSpec) + (*in).DeepCopyInto(*out) + } + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstream. +func (in *ApisixUpstream) DeepCopy() *ApisixUpstream { + if in == nil { + return nil + } + out := new(ApisixUpstream) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApisixUpstream) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstreamConfig) DeepCopyInto(out *ApisixUpstreamConfig) { + *out = *in + if in.LoadBalancer != nil { + in, out := &in.LoadBalancer, &out.LoadBalancer + *out = new(LoadBalancer) + **out = **in + } + if in.Retries != nil { + in, out := &in.Retries, &out.Retries + *out = new(int) + **out = **in + } + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(UpstreamTimeout) + **out = **in + } + if in.HealthCheck != nil { + in, out := &in.HealthCheck, &out.HealthCheck + *out = new(HealthCheck) + (*in).DeepCopyInto(*out) + } + if in.TLSSecret != nil { + in, out := &in.TLSSecret, &out.TLSSecret + *out = new(ApisixSecret) + **out = **in + } + if in.Subsets != nil { + in, out := &in.Subsets, &out.Subsets + *out = make([]ApisixUpstreamSubset, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstreamConfig. +func (in *ApisixUpstreamConfig) DeepCopy() *ApisixUpstreamConfig { + if in == nil { + return nil + } + out := new(ApisixUpstreamConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstreamExternalNode) DeepCopyInto(out *ApisixUpstreamExternalNode) { + *out = *in + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int) + **out = **in + } + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstreamExternalNode. +func (in *ApisixUpstreamExternalNode) DeepCopy() *ApisixUpstreamExternalNode { + if in == nil { + return nil + } + out := new(ApisixUpstreamExternalNode) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstreamExternalType) DeepCopyInto(out *ApisixUpstreamExternalType) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstreamExternalType. +func (in *ApisixUpstreamExternalType) DeepCopy() *ApisixUpstreamExternalType { + if in == nil { + return nil + } + out := new(ApisixUpstreamExternalType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstreamList) DeepCopyInto(out *ApisixUpstreamList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ApisixUpstream, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstreamList. +func (in *ApisixUpstreamList) DeepCopy() *ApisixUpstreamList { + if in == nil { + return nil + } + out := new(ApisixUpstreamList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApisixUpstreamList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstreamSpec) DeepCopyInto(out *ApisixUpstreamSpec) { + *out = *in + if in.ExternalNodes != nil { + in, out := &in.ExternalNodes, &out.ExternalNodes + *out = make([]ApisixUpstreamExternalNode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.ApisixUpstreamConfig.DeepCopyInto(&out.ApisixUpstreamConfig) + if in.PortLevelSettings != nil { + in, out := &in.PortLevelSettings, &out.PortLevelSettings + *out = make([]PortLevelSettings, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstreamSpec. +func (in *ApisixUpstreamSpec) DeepCopy() *ApisixUpstreamSpec { + if in == nil { + return nil + } + out := new(ApisixUpstreamSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixUpstreamSubset) DeepCopyInto(out *ApisixUpstreamSubset) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixUpstreamSubset. +func (in *ApisixUpstreamSubset) DeepCopy() *ApisixUpstreamSubset { + if in == nil { + return nil + } + out := new(ApisixUpstreamSubset) + in.DeepCopyInto(out) + return out +} + + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HealthCheck) DeepCopyInto(out *HealthCheck) { + *out = *in + if in.Active != nil { + in, out := &in.Active, &out.Active + *out = new(ActiveHealthCheck) + (*in).DeepCopyInto(*out) + } + if in.Passive != nil { + in, out := &in.Passive, &out.Passive + *out = new(PassiveHealthCheck) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheck. +func (in *HealthCheck) DeepCopy() *HealthCheck { + if in == nil { + return nil + } + out := new(HealthCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancer. +func (in *LoadBalancer) DeepCopy() *LoadBalancer { + if in == nil { + return nil + } + out := new(LoadBalancer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PassiveHealthCheck) DeepCopyInto(out *PassiveHealthCheck) { + *out = *in + if in.Healthy != nil { + in, out := &in.Healthy, &out.Healthy + *out = new(PassiveHealthCheckHealthy) + (*in).DeepCopyInto(*out) + } + if in.Unhealthy != nil { + in, out := &in.Unhealthy, &out.Unhealthy + *out = new(PassiveHealthCheckUnhealthy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthCheck. +func (in *PassiveHealthCheck) DeepCopy() *PassiveHealthCheck { + if in == nil { + return nil + } + out := new(PassiveHealthCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PassiveHealthCheckHealthy) DeepCopyInto(out *PassiveHealthCheckHealthy) { + *out = *in + if in.HTTPCodes != nil { + in, out := &in.HTTPCodes, &out.HTTPCodes + *out = make([]int, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthCheckHealthy. +func (in *PassiveHealthCheckHealthy) DeepCopy() *PassiveHealthCheckHealthy { + if in == nil { + return nil + } + out := new(PassiveHealthCheckHealthy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PassiveHealthCheckUnhealthy) DeepCopyInto(out *PassiveHealthCheckUnhealthy) { + *out = *in + if in.HTTPCodes != nil { + in, out := &in.HTTPCodes, &out.HTTPCodes + *out = make([]int, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthCheckUnhealthy. +func (in *PassiveHealthCheckUnhealthy) DeepCopy() *PassiveHealthCheckUnhealthy { + if in == nil { + return nil + } + out := new(PassiveHealthCheckUnhealthy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortLevelSettings) DeepCopyInto(out *PortLevelSettings) { + *out = *in + in.ApisixUpstreamConfig.DeepCopyInto(&out.ApisixUpstreamConfig) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortLevelSettings. +func (in *PortLevelSettings) DeepCopy() *PortLevelSettings { + if in == nil { + return nil + } + out := new(PortLevelSettings) + in.DeepCopyInto(out) + return out +} + + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActiveHealthCheck) DeepCopyInto(out *ActiveHealthCheck) { + *out = *in + if in.StrictTLS != nil { + in, out := &in.StrictTLS, &out.StrictTLS + *out = new(bool) + **out = **in + } + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Healthy != nil { + in, out := &in.Healthy, &out.Healthy + *out = new(ActiveHealthCheckHealthy) + (*in).DeepCopyInto(*out) + } + if in.Unhealthy != nil { + in, out := &in.Unhealthy, &out.Unhealthy + *out = new(ActiveHealthCheckUnhealthy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActiveHealthCheck. +func (in *ActiveHealthCheck) DeepCopy() *ActiveHealthCheck { + if in == nil { + return nil + } + out := new(ActiveHealthCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActiveHealthCheckHealthy) DeepCopyInto(out *ActiveHealthCheckHealthy) { + *out = *in + in.PassiveHealthCheckHealthy.DeepCopyInto(&out.PassiveHealthCheckHealthy) + out.Interval = in.Interval + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActiveHealthCheckHealthy. +func (in *ActiveHealthCheckHealthy) DeepCopy() *ActiveHealthCheckHealthy { + if in == nil { + return nil + } + out := new(ActiveHealthCheckHealthy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActiveHealthCheckUnhealthy) DeepCopyInto(out *ActiveHealthCheckUnhealthy) { + *out = *in + in.PassiveHealthCheckUnhealthy.DeepCopyInto(&out.PassiveHealthCheckUnhealthy) + out.Interval = in.Interval + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActiveHealthCheckUnhealthy. +func (in *ActiveHealthCheckUnhealthy) DeepCopy() *ActiveHealthCheckUnhealthy { + if in == nil { + return nil + } + out := new(ActiveHealthCheckUnhealthy) + in.DeepCopyInto(out) + return out +} \ No newline at end of file