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

Use an array instead of a string for the FQDN parameter #269

Merged
merged 5 commits into from
Nov 26, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apis/vshn/v1/vshn_nextcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,12 @@ type VSHNNextcloudServiceSpec struct {
// Collabora contains settings to control the Collabora integration.
Collabora CollaboraSpec `json:"collabora,omitempty"`
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinItems=1

// FQDN contains the FQDN which will be used for the ingress.
// FQDN contains the FQDNs array, which will be used for the ingress.
// If it's not set, no ingress will be deployed.
// This also enables strict hostname checking for this FQDN.
FQDN string `json:"fqdn"`
FQDN []string `json:"fqdn"`
TheBigLee marked this conversation as resolved.
Show resolved Hide resolved

// RelativePath on which Nextcloud will listen.
// +kubebuilder:default="/"
Expand Down
5 changes: 5 additions & 0 deletions apis/vshn/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions crds/vshn.appcat.vshn.io_vshnnextclouds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4866,10 +4866,13 @@ spec:
type: object
fqdn:
description: |-
FQDN contains the FQDN which will be used for the ingress.
FQDN contains the FQDNs array, which will be used for the ingress.
If it's not set, no ingress will be deployed.
This also enables strict hostname checking for this FQDN.
type: string
items:
type: string
minItems: 1
type: array
postgreSQLParameters:
description: |-
PostgreSQLParameters can be used to set any supported setting in the
Expand Down
7 changes: 5 additions & 2 deletions crds/vshn.appcat.vshn.io_xvshnnextclouds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5595,10 +5595,13 @@ spec:
type: object
fqdn:
description: |-
FQDN contains the FQDN which will be used for the ingress.
FQDN contains the FQDNs array, which will be used for the ingress.
If it's not set, no ingress will be deployed.
This also enables strict hostname checking for this FQDN.
type: string
items:
type: string
minItems: 1
type: array
postgreSQLParameters:
description: |-
PostgreSQLParameters can be used to set any supported setting in the
Expand Down
5 changes: 0 additions & 5 deletions pkg/comp-functions/functions/vshnnextcloud/collabora.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"encoding/pem"
"fmt"

valid "github.com/asaskevich/govalidator"
cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
xfnproto "github.com/crossplane/function-sdk-go/proto/v1beta1"
Expand Down Expand Up @@ -53,10 +52,6 @@ func DeployCollabora(ctx context.Context, comp *vshnv1.VSHNNextcloud, svc *runti
return runtime.NewNormalResult("Collabora not enabled")
}

if !valid.IsDNSName(comp.Spec.Parameters.Service.Collabora.FQDN) {
return runtime.NewWarningResult("Collabora FQDN is not a valid DNS name: " + comp.Spec.Parameters.Service.Collabora.FQDN)
}

rules := []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Expand Down
7 changes: 0 additions & 7 deletions pkg/comp-functions/functions/vshnnextcloud/collabora_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,4 @@ func Test_addCollabora(t *testing.T) {
res = DeployCollabora(ctx, comp, svc)

assert.True(t, res.Severity == v1beta1.Severity_SEVERITY_NORMAL && res.Message == "Collabora not enabled")

zugao marked this conversation as resolved.
Show resolved Hide resolved
comp.Spec.Parameters.Service.Collabora.Enabled = true
comp.Spec.Parameters.Service.Collabora.FQDN = ""
res = DeployCollabora(ctx, comp, svc)

assert.True(t, res.Severity == v1beta1.Severity_SEVERITY_WARNING && res.Message == "Collabora FQDN is not a valid DNS name: "+comp.Spec.Parameters.Service.Collabora.FQDN)

}
18 changes: 17 additions & 1 deletion pkg/comp-functions/functions/vshnnextcloud/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

valid "github.com/asaskevich/govalidator"
xfnproto "github.com/crossplane/function-sdk-go/proto/v1beta1"
xhelmv1 "github.com/vshn/appcat/v4/apis/helm/release/v1beta1"
vshnv1 "github.com/vshn/appcat/v4/apis/vshn/v1"
Expand Down Expand Up @@ -256,10 +257,16 @@ func newValues(ctx context.Context, svc *runtime.ServiceRuntime, comp *vshnv1.VS
}
}

trustedDomain := []string{
comp.GetName() + "." + comp.GetInstanceNamespace() + ".svc.cluster.local",
}
trustedDomain = append(trustedDomain, comp.Spec.Parameters.Service.FQDN...)
TheBigLee marked this conversation as resolved.
Show resolved Hide resolved

updatedNextcloudConfig := setBackgroundJobMaintenance(comp.Spec.Parameters.Maintenance.GetMaintenanceTimeOfDay(), nextcloudConfig)
values = map[string]any{
"nextcloud": map[string]any{
"host": comp.Spec.Parameters.Service.FQDN,
"host": comp.Spec.Parameters.Service.FQDN[0],
"trustedDomains": trustedDomain,
"existingSecret": map[string]any{
"enabled": true,
"secretName": adminSecret,
Expand Down Expand Up @@ -428,3 +435,12 @@ func setBackgroundJobMaintenance(t vshnv1.TimeOfDay, nextcloudConfig string) str
backgroundJobHour := t.GetTime().Add(40 * time.Minute).Add(time.Hour).Hour()
return strings.Replace(nextcloudConfig, "%maintenance_value%", strconv.Itoa(backgroundJobHour), 1)
}

func validateFQDNs(fqdns []string) error {
for _, fqdn := range fqdns {
if !valid.IsDNSName(fqdn) {
TheBigLee marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("FQDN %s is not a valid DNS name", fqdn)
}
}
return nil
}
108 changes: 55 additions & 53 deletions pkg/comp-functions/functions/vshnnextcloud/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package vshnnextcloud

import (
"context"
"encoding/json"
"errors"
"fmt"

xfnproto "github.com/crossplane/function-sdk-go/proto/v1beta1"
xhelmv1 "github.com/vshn/appcat/v4/apis/helm/release/v1beta1"
vshnv1 "github.com/vshn/appcat/v4/apis/vshn/v1"
"github.com/vshn/appcat/v4/pkg/comp-functions/functions/common"
"github.com/vshn/appcat/v4/pkg/comp-functions/runtime"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
netv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
)

// AddIngress adds an inrgess to the Nextcloud instance.
Expand All @@ -22,69 +22,71 @@ func AddIngress(_ context.Context, comp *vshnv1.VSHNNextcloud, svc *runtime.Serv
return runtime.NewFatalResult(fmt.Errorf("cannot get composite: %w", err))
}

if comp.Spec.Parameters.Service.FQDN == "" {
return nil
if len(comp.Spec.Parameters.Service.FQDN) == 0 {
return runtime.NewFatalResult(fmt.Errorf("FQDN array is empty, but requires at least one entry, %w", errors.New("empty fqdn")))
}

values, err := common.GetDesiredReleaseValues(svc, comp.GetName()+"-release")
if err != nil {
return runtime.NewWarningResult(fmt.Sprintf("cannot get desired release values: %s", err))
}

svc.Log.Info("Enable ingress for release")
enableIngresValues(svc, comp, values)

release := &xhelmv1.Release{}
err = svc.GetDesiredComposedResourceByName(release, comp.GetName()+"-release")
if err != nil {
return runtime.NewWarningResult(fmt.Sprintf("cannot get desired release: %s", err))
annotations := map[string]string{}
if svc.Config.Data["ingress_annotations"] != "" {
err := yaml.Unmarshal([]byte(svc.Config.Data["ingress_annotations"]), annotations)
if err != nil {
svc.Log.Error(err, "cannot unmarshal ingress annotations from input")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot unmarshal ingress annotations from input: %s", err)))
}
}

vb, err := json.Marshal(values)
if err != nil {
return runtime.NewWarningResult(fmt.Sprintf("cannot marhal values: %s", err))
ingress := &netv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName(),
Namespace: comp.GetInstanceNamespace(),
Annotations: annotations,
},
Spec: netv1.IngressSpec{
Rules: createIngressRule(comp),
TLS: []netv1.IngressTLS{
{
Hosts: comp.Spec.Parameters.Service.FQDN,
SecretName: "nextcloud-ingress-cert",
},
},
},
}

release.Spec.ForProvider.Values.Raw = vb

err = svc.SetDesiredComposedResourceWithName(release, comp.GetName()+"-release")
err = svc.SetDesiredKubeObject(ingress, comp.GetName()+"-ingress")
if err != nil {
return runtime.NewWarningResult(fmt.Sprintf("cannot set desired release: %s", err))
return runtime.NewWarningResult(fmt.Sprintf("cannot set create ingress: %s", err))
}

return nil
}

func enableIngresValues(svc *runtime.ServiceRuntime, comp *vshnv1.VSHNNextcloud, values map[string]any) {
fqdn := comp.Spec.Parameters.Service.FQDN

values["ingress"] = map[string]any{
"enabled": true,
"servicePort": "http",
"path": comp.Spec.Parameters.Service.RelativePath,
"tls": []map[string]any{
{
"hosts": []string{
fqdn,
func createIngressRule(comp *vshnv1.VSHNNextcloud) []netv1.IngressRule {

ingressRules := []netv1.IngressRule{}

for _, fqdn := range comp.Spec.Parameters.Service.FQDN {
rule := netv1.IngressRule{
Host: fqdn,
IngressRuleValue: netv1.IngressRuleValue{
HTTP: &netv1.HTTPIngressRuleValue{
Paths: []netv1.HTTPIngressPath{
{
Path: "/",
PathType: ptr.To(netv1.PathType("Prefix")),
Backend: netv1.IngressBackend{
Service: &netv1.IngressServiceBackend{
Name: comp.GetName(),
Port: netv1.ServiceBackendPort{
Number: 8080,
},
},
},
},
},
},
"secretName": "nextcloud-ingress-cert",
},
},
}

if svc.Config.Data["ingress_annotations"] != "" {
annotations := map[string]any{}

err := yaml.Unmarshal([]byte(svc.Config.Data["ingress_annotations"]), annotations)
if err != nil {
svc.Log.Error(err, "cannot unmarshal ingress annotations from input")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot unmarshal ingress annotations from input: %s", err)))
}

err = unstructured.SetNestedMap(values, annotations, "ingress", "annotations")
if err != nil {
svc.Log.Error(err, "cannot set ingress annotations")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot set ingress annotations: %s", err)))
}
ingressRules = append(ingressRules, rule)
}
return ingressRules
}
Loading
Loading