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

v2alpha1 support for short hosts #1311

Merged
merged 27 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a4e7ea9
Short host validation
videlov Sep 19, 2024
028a98f
More validation
videlov Sep 19, 2024
7f98f1b
Default domain from non-kyma gateway
videlov Sep 19, 2024
6ed8290
State
videlov Sep 22, 2024
3cfb14c
State
videlov Sep 23, 2024
738da6b
integration test
videlov Sep 24, 2024
61dd290
Renamings and docs update
videlov Sep 24, 2024
fd39bf4
Update internal/validation/v2alpha1/hosts.go
videlov Sep 24, 2024
ab44d4e
Review naming suggestions
videlov Sep 24, 2024
01a51ec
Update error message
videlov Sep 24, 2024
c13f012
Cover case for Istio gateway with host definition "*."
videlov Sep 24, 2024
8255e4c
Fix
videlov Sep 24, 2024
c4348fe
Error on APIRule when Gateway not found
videlov Sep 24, 2024
15fce55
Fix integration test
videlov Sep 24, 2024
7fd5421
Update internal/validation/v2alpha1/hosts.go
videlov Sep 25, 2024
9cc0e93
Update docs/contributor/adr/0007-apirule-v2alpha1-api-proposal.md
videlov Sep 25, 2024
3d843bc
Update internal/helpers/hosts.go
videlov Sep 25, 2024
51c4ad4
Review adjustments
videlov Sep 25, 2024
d0802db
Fix lint
videlov Sep 25, 2024
4077c1f
Review suggestion re-correction
videlov Sep 25, 2024
dbe830e
Fix int test v2alpha1 status checks and adds error int scenario for s…
videlov Sep 25, 2024
e71efa2
Unwanted removal
videlov Sep 25, 2024
63d2259
Fix error message
videlov Sep 25, 2024
6aa8442
Revert v2alpha1 integration test use new status check func
videlov Sep 25, 2024
dd15309
Update docs/user/custom-resources/apirule/v2alpha1/04-10-apirule-cust…
videlov Sep 26, 2024
b06ed25
Update docs/user/custom-resources/apirule/v2alpha1/04-10-apirule-cust…
videlov Sep 26, 2024
4d0a37a
Fix v2alpha1 int tests with original function for applying
videlov Sep 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions apis/gateway/v2alpha1/apirule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ type APIRuleSpec struct {
Timeout *Timeout `json:"timeout,omitempty"`
}

// Host is the URL of the exposed service.
// +kubebuilder:validation:MinLength=3
// Host is the URL of the exposed service. We support lowercase RFC 1123 labels and FQDN.
// +kubebuilder:validation:MaxLength=255
// +kubebuilder:validation:XValidation:rule=`self.matches('^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$')`,message="Host is not Fully Qualified Domain Name"
// +kubebuilder:validation:XValidation:rule=`self.matches('^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9])*$')`,message="Host must be a lowercase RFC 1123 label (must consist of lowercase alphanumeric characters or '-', and must start and end with an lowercase alphanumeric character) or a fully qualified domain name"
type Host string

// APIRuleStatus describes the observed state of ApiRule.
Expand Down
11 changes: 7 additions & 4 deletions config/crd/bases/gateway.kyma-project.io_apirules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,16 @@ spec:
hosts:
description: Specifies the URLs of the exposed service.
items:
description: Host is the URL of the exposed service.
description: Host is the URL of the exposed service. We support
lowercase RFC 1123 labels and FQDN.
maxLength: 255
minLength: 3
type: string
x-kubernetes-validations:
- message: Host is not Fully Qualified Domain Name
rule: self.matches('^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$')
- message: Host must be a lowercase RFC 1123 label (must consist
of lowercase alphanumeric characters or '-', and must start
and end with an lowercase alphanumeric character) or a fully
qualified domain name
rule: self.matches('^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9])*$')
maxItems: 1
minItems: 1
type: array
Expand Down
899 changes: 465 additions & 434 deletions controllers/gateway/api_controller_integration_test.go

Large diffs are not rendered by default.

52 changes: 40 additions & 12 deletions controllers/gateway/apirule_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ package gateway
import (
"context"
"fmt"
"strings"
"time"

"github.com/kyma-project/api-gateway/internal/dependencies"
"github.com/kyma-project/api-gateway/internal/processing/processors/migration"
"github.com/kyma-project/api-gateway/internal/processing/status"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"time"

gatewayv1beta1 "github.com/kyma-project/api-gateway/apis/gateway/v1beta1"
gatewayv2alpha1 "github.com/kyma-project/api-gateway/apis/gateway/v2alpha1"
Expand All @@ -44,6 +47,7 @@ import (

"github.com/go-logr/logr"
"github.com/kyma-project/api-gateway/internal/processing"
networkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
corev1 "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -77,7 +81,7 @@ func (r *APIRuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
l.Info("Starting reconciliation")
ctx = logr.NewContext(ctx, r.Log)

defaultDomainName, err := default_domain.GetDefaultDomainFromKymaGateway(ctx, r.Client)
defaultDomainName, err := default_domain.GetDomainFromKymaGateway(ctx, r.Client)
if err != nil && default_domain.HandleDefaultDomainError(l, err) {
return doneReconcileErrorRequeue(err, errorReconciliationPeriod)
}
Expand Down Expand Up @@ -117,11 +121,11 @@ func (r *APIRuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
}

if r.isApiRuleConvertedFromV2alpha1(apiRule) {
return r.reconcileV2alpha1APIRule(ctx, l, apiRule, defaultDomainName)
return r.reconcileV2Alpha1APIRule(ctx, l, apiRule)
}

l.Info("Reconciling v1beta1 APIRule", "jwtHandler", r.Config.JWTHandler)
cmd := r.getV1beta1Reconciliation(&apiRule, defaultDomainName, &l)
cmd := r.getV1Beta1Reconciliation(&apiRule, defaultDomainName, &l)
if name, err := dependencies.APIRule().AreAvailable(ctx, r.Client); err != nil {
s, err := handleDependenciesError(name, err).V1beta1Status()
if err != nil {
Expand Down Expand Up @@ -157,7 +161,7 @@ func (r *APIRuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
return r.updateStatus(ctx, l, &apiRule)
}

func (r *APIRuleReconciler) reconcileV2alpha1APIRule(ctx context.Context, l logr.Logger, apiRule gatewayv1beta1.APIRule, domain string) (ctrl.Result, error) {
func (r *APIRuleReconciler) reconcileV2Alpha1APIRule(ctx context.Context, l logr.Logger, apiRule gatewayv1beta1.APIRule) (ctrl.Result, error) {
l.Info("Reconciling v2alpha1 APIRule")
toUpdate := apiRule.DeepCopy()
migrate, err := apiRuleNeedsMigration(ctx, r.Client, toUpdate)
Expand All @@ -179,8 +183,33 @@ func (r *APIRuleReconciler) reconcileV2alpha1APIRule(ctx context.Context, l logr
if err := rule.ConvertFrom(toUpdate); err != nil {
return doneReconcileErrorRequeue(err, r.OnErrorReconcilePeriod)
}
cmd := r.getv2alpha1Reconciliation(&apiRule, &rule,
domain, migrate, &l)

gatewayName := strings.Split(*rule.Spec.Gateway, "/")
gatewayNN := types.NamespacedName{
Namespace: gatewayName[0],
Name: gatewayName[1],
}
var gateway networkingv1beta1.Gateway
if err := r.Client.Get(ctx, gatewayNN, &gateway); err != nil {
v2Alpha1Status := status.ReconciliationV2alpha1Status{
ApiRuleStatus: &gatewayv2alpha1.APIRuleStatus{
State: gatewayv2alpha1.State(gatewayv2alpha1.Error),
},
}
s := v2Alpha1Status.GenerateStatusFromFailures([]validation.Failure{
{
AttributePath: "spec.gateway",
Message: "Could not get specified Gateway",
},
})
if err := s.UpdateStatus(&rule.Status); err != nil {
l.Error(err, "Error updating APIRule status")
return doneReconcileErrorRequeue(err, r.OnErrorReconcilePeriod)
}
return r.convertAndUpdateStatus(ctx, l, rule)
}

cmd := r.getV2Alpha1Reconciliation(&apiRule, &rule, &gateway, migrate, &l)

if name, err := dependencies.APIRule().AreAvailable(ctx, r.Client); err != nil {
s, err := handleDependenciesError(name, err).V2alpha1Status()
Expand Down Expand Up @@ -256,9 +285,9 @@ func handleDependenciesError(name string, err error) controllers.Status {
}
}

func (r *APIRuleReconciler) getV1beta1Reconciliation(apiRule *gatewayv1beta1.APIRule, defaultDomain string, namespacedLogger *logr.Logger) processing.ReconciliationCommand {
func (r *APIRuleReconciler) getV1Beta1Reconciliation(apiRule *gatewayv1beta1.APIRule, defaultDomainName string, namespacedLogger *logr.Logger) processing.ReconciliationCommand {
config := r.ReconciliationConfig
config.DefaultDomainName = defaultDomain
config.DefaultDomainName = defaultDomainName
switch {
case r.Config.JWTHandler == helpers.JWT_HANDLER_ISTIO:
return istio.NewIstioReconciliation(apiRule, config, namespacedLogger)
Expand All @@ -267,11 +296,10 @@ func (r *APIRuleReconciler) getV1beta1Reconciliation(apiRule *gatewayv1beta1.API
}
}

func (r *APIRuleReconciler) getv2alpha1Reconciliation(apiRulev1beta1 *gatewayv1beta1.APIRule, apiRulev2alpha1 *gatewayv2alpha1.APIRule, defaultDomain string, needsMigration bool, namespacedLogger *logr.Logger) processing.ReconciliationCommand {
func (r *APIRuleReconciler) getV2Alpha1Reconciliation(apiRulev1beta1 *gatewayv1beta1.APIRule, apiRulev2alpha1 *gatewayv2alpha1.APIRule, gateway *networkingv1beta1.Gateway, needsMigration bool, namespacedLogger *logr.Logger) processing.ReconciliationCommand {
config := r.ReconciliationConfig
config.DefaultDomainName = defaultDomain
v2alpha1Validator := v2alpha1.NewAPIRuleValidator(apiRulev2alpha1)
return v2alpha1Processing.NewReconciliation(apiRulev2alpha1, apiRulev1beta1, v2alpha1Validator, config, namespacedLogger, needsMigration)
return v2alpha1Processing.NewReconciliation(apiRulev2alpha1, apiRulev1beta1, gateway, v2alpha1Validator, config, namespacedLogger, needsMigration)
}

// SetupWithManager sets up the controller with the Manager.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Due to the deprecation of Ory and the introduction of new features in API Gatewa
| **corsPolicy.allowCredentials** | **NO** | Specifies whether credentials are allowed in the **Access-Control-Allow-Credentials** CORS header. | |
| **corsPolicy.exposeHeaders** | **NO** | Specifies headers exposed with the **Access-Control-Expose-Headers** CORS header. | |
| **corsPolicy.maxAge** | **NO** | Specifies the maximum age of CORS policy cache. The value is provided in the **Access-Control-Max-Age** CORS header. | |
| **hosts** | **YES** | Specifies the Service's communication address for inbound external traffic. If only the leftmost label is provided, the default domain name is used. | The full domain name or the leftmost label cannot contain the wildcard character `*`. |
| **hosts** | **YES** | Specifies the Service's communication address for inbound external traffic. If only the leftmost label is provided, the domain name from the referenced Gateway is used, expanding the host to `<label>.<gateway domain>`. | The full domain name or the leftmost label cannot contain the wildcard character `*`. |
| **service.name** | **NO** | Specifies the name of the exposed Service. | |
| **service.namespace** | **NO** | Specifies the namespace of the exposed Service. | |
| **service.port** | **NO** | Specifies the communication port of the exposed Service. | |
Expand Down
5 changes: 4 additions & 1 deletion docs/release-notes/2.7.0.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## New Features

- Add support for short host name for APIRule in version `v2alpha1` [#1311](https://github.com/kyma-project/api-gateway/pull/1311)

## Bug fixes

- Fix the wildcard path format and the validation of the rule path in an APIRule [#1285](https://github.com/kyma-project/api-gateway/pull/1285)
- Fix the wildcard path format and the validation of the rule path in an APIRule [#1285](https://github.com/kyma-project/api-gateway/pull/1285)
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This table lists all parameters of APIRule `v2alpha1` CRD together with their de
| **corsPolicy.allowCredentials** | **NO** | Specifies whether credentials are allowed in the **Access-Control-Allow-Credentials** CORS header. | None |
| **corsPolicy.exposeHeaders** | **NO** | Specifies headers exposed with the **Access-Control-Expose-Headers** CORS header. | None |
| **corsPolicy.maxAge** | **NO** | Specifies the maximum age of CORS policy cache. The value is provided in the **Access-Control-Max-Age** CORS header. | None |
| **hosts** | **YES** | Specifies the Service's communication address for inbound external traffic. It must be a fully qualified domain name in proper FQDN format: at least two domain labels with characters, numbers, or dashes. | FQDN format. |
| **hosts** | **YES** | Specifies the Service's communication address for inbound external traffic. It must be a RFC 1123 label or a valid, fully qualified domain name (FQDN) in the following format: at least two domain labels with characters, numbers, or hyphens. | Lowercase RFC 1123 label or FQDN format. |
| **service.name** | **NO** | Specifies the name of the exposed Service. | None |
| **service.namespace** | **NO** | Specifies the namespace of the exposed Service. | None |
| **service.port** | **NO** | Specifies the communication port of the exposed Service. | None |
Expand Down Expand Up @@ -61,6 +61,9 @@ This table lists all parameters of APIRule `v2alpha1` CRD together with their de
> [!WARNING]
> If a service is not defined at the **spec.service** level, all defined Access Rules must have it defined at the **spec.rules.service** level. Otherwise, the validation fails.

> [!WARNING]
> If a short host name is defined at the **spec.hosts** level, the referenced Gateway must provide the same single host for all [Server](https://istio.io/latest/docs/reference/config/networking/gateway/#Server) definitions and it must be prefixed with `*.`. Otherwise, the validation fails.

**Status:**

The following table lists the fields of the **status** section.
Expand Down Expand Up @@ -93,3 +96,25 @@ spec:
methods: [ "GET" ]
noAuth: true
```

This sample APIRule illustrates the usage of a short host name. It uses the domain from the referenced Gateway `kyma-system/kyma-gateway`:

```yaml
apiVersion: gateway.kyma-project.io/v2alpha1
kind: APIRule
metadata:
name: service-exposed
spec:
gateway: kyma-system/kyma-gateway
hosts:
- foo
service:
name: foo-service
namespace: foo-namespace
port: 8080
timeout: 360
rules:
- path: /*
methods: [ "GET" ]
noAuth: true
```
Loading
Loading