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 API served via HTTPS when preferService: true #772

Merged
merged 4 commits into from Jun 12, 2022
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
15 changes: 14 additions & 1 deletion controllers/grafana/grafana_controller.go
Expand Up @@ -269,7 +269,20 @@ func (r *ReconcileGrafana) getGrafanaAdminUrl(cr *grafanav1alpha1.Grafana, state

// Otherwise rely on the service
if state.GrafanaService != nil {
return fmt.Sprintf("http://%v.%v.svc.cluster.local:%d", state.GrafanaService.Name, cr.Namespace,
protocol := "http"

if cr.Spec.Config.Server != nil {
switch cr.Spec.Config.Server.Protocol {
case "", "http":
protocol = "http"
case "https":
protocol = "https"
default:
return "", stdErr.New(fmt.Sprintf("server protocol %v is not supported, please use either http or https", protocol))
}
}

return fmt.Sprintf("%v://%v.%v.svc.cluster.local:%d", protocol, state.GrafanaService.Name, cr.Namespace,
servicePort), nil
}

Expand Down
215 changes: 215 additions & 0 deletions controllers/grafana/grafana_controller_test.go
@@ -0,0 +1,215 @@
package grafana

import (
"testing"

grafanav1alpha1 "github.com/grafana-operator/grafana-operator/v4/api/integreatly/v1alpha1"
"github.com/grafana-operator/grafana-operator/v4/controllers/common"
routev1 "github.com/openshift/api/route/v1"

"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
netv1 "k8s.io/api/networking/v1"
)

func TestReconcileGrafana_getGrafanaAdminUrl(t *testing.T) {
r := &ReconcileGrafana{}

/*
Service is NOT preferred
*/

t.Run("Route", func(t *testing.T) {
cr := &grafanav1alpha1.Grafana{}

state := &common.ClusterState{
GrafanaRoute: &routev1.Route{
Spec: routev1.RouteSpec{
Host: "route",
},
},
}
want := "https://route"

got, err := r.getGrafanaAdminUrl(cr, state)
assert.Nil(t, err)
assert.Equal(t, want, got)
})

t.Run("Ingress", func(t *testing.T) {
cr := &grafanav1alpha1.Grafana{
Spec: grafanav1alpha1.GrafanaSpec{
Ingress: &grafanav1alpha1.GrafanaIngress{
Hostname: "ingress",
},
},
}

state := &common.ClusterState{
GrafanaIngress: &netv1.Ingress{},
}

want := "https://ingress"

got, err := r.getGrafanaAdminUrl(cr, state)
assert.Nil(t, err)
assert.Equal(t, want, got)
})

t.Run("Ingress with empty spec, LB with Hostname", func(t *testing.T) {
cr := &grafanav1alpha1.Grafana{
Spec: grafanav1alpha1.GrafanaSpec{
Ingress: &grafanav1alpha1.GrafanaIngress{},
},
}

state := &common.ClusterState{
GrafanaIngress: &netv1.Ingress{
Status: netv1.IngressStatus{
LoadBalancer: v1.LoadBalancerStatus{
Ingress: []v1.LoadBalancerIngress{
{
Hostname: "lbhostname",
},
},
},
},
},
}

want := "https://lbhostname"

got, err := r.getGrafanaAdminUrl(cr, state)
assert.Nil(t, err)
assert.Equal(t, want, got)
})

t.Run("Ingress with empty spec, LB with IP", func(t *testing.T) {
cr := &grafanav1alpha1.Grafana{
Spec: grafanav1alpha1.GrafanaSpec{
Ingress: &grafanav1alpha1.GrafanaIngress{},
},
}

state := &common.ClusterState{
GrafanaIngress: &netv1.Ingress{
Status: netv1.IngressStatus{
LoadBalancer: v1.LoadBalancerStatus{
Ingress: []v1.LoadBalancerIngress{
{
IP: "1.2.3.4",
},
},
},
},
},
}

want := "https://1.2.3.4"

got, err := r.getGrafanaAdminUrl(cr, state)
assert.Nil(t, err)
assert.Equal(t, want, got)
})

t.Run("Empty specs", func(t *testing.T) {
cr := &grafanav1alpha1.Grafana{}

state := &common.ClusterState{}

_, err := r.getGrafanaAdminUrl(cr, state)
assert.NotNil(t, err)
})

/*
Service IS preferred
*/

type Srv = grafanav1alpha1.GrafanaConfigServer

testsPreferService := []struct {
name string
server *Srv
want string
wantFail bool
}{
{
name: "server spec is nil",
server: nil,
want: "http://grafana.monitoring.svc.cluster.local:3000",
wantFail: false,
},
{
name: "server protocol: not specified",
server: &Srv{Protocol: ""},
want: "http://grafana.monitoring.svc.cluster.local:3000",
wantFail: false,
},
{
name: "server protocol: http",
server: &Srv{Protocol: "http"},
want: "http://grafana.monitoring.svc.cluster.local:3000",
wantFail: false,
},
{
name: "server protocol: https",
server: &Srv{Protocol: "https"},
want: "https://grafana.monitoring.svc.cluster.local:3000",
wantFail: false,
},
{
name: "server protocol: h2",
server: &Srv{Protocol: "h2"},
want: "",
wantFail: true,
},
{
name: "server protocol: socket",
server: &Srv{Protocol: "socket"},
want: "",
wantFail: true,
},
}

for _, tt := range testsPreferService {
preferService := true

t.Run(tt.name, func(t *testing.T) {
cr := &grafanav1alpha1.Grafana{
Spec: grafanav1alpha1.GrafanaSpec{
// Ingress is set only to make sure PreferService is respected
Ingress: &grafanav1alpha1.GrafanaIngress{
Hostname: "ingress",
},
Client: &grafanav1alpha1.GrafanaClient{
PreferService: &preferService,
},
Config: grafanav1alpha1.GrafanaConfig{
Server: tt.server,
},
},
}
cr.Namespace = "monitoring"

state := &common.ClusterState{
// GrafanaRoute is set only to make sure PreferService is respected
GrafanaRoute: &routev1.Route{
Spec: routev1.RouteSpec{
Host: "route",
},
},
GrafanaService: &v1.Service{},
}
state.GrafanaService.Name = "grafana"

got, err := r.getGrafanaAdminUrl(cr, state)

if tt.wantFail {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, tt.want, got)
}
})
}
}
6 changes: 6 additions & 0 deletions controllers/model/grafanaDeployment.go
Expand Up @@ -452,6 +452,9 @@ func getLivenessProbe(cr *v1alpha1.Grafana, delay, timeout, failure int32) *v13.
var period int32 = 10
var success int32 = 1
var scheme = v13.URISchemeHTTP
if cr.Spec.Config.Server != nil && cr.Spec.Config.Server.Protocol == "https" {
scheme = v13.URISchemeHTTPS
}

if cr.Spec.LivenessProbeSpec != nil && cr.Spec.LivenessProbeSpec.InitialDelaySeconds != nil {
delay = *cr.Spec.LivenessProbeSpec.InitialDelaySeconds
Expand Down Expand Up @@ -497,6 +500,9 @@ func getReadinessProbe(cr *v1alpha1.Grafana, delay, timeout, failure int32) *v13
var period int32 = 10
var success int32 = 1
var scheme = v13.URISchemeHTTP
if cr.Spec.Config.Server != nil && cr.Spec.Config.Server.Protocol == "https" {
scheme = v13.URISchemeHTTPS
}

if cr.Spec.ReadinessProbeSpec != nil && cr.Spec.ReadinessProbeSpec.InitialDelaySeconds != nil {
delay = *cr.Spec.ReadinessProbeSpec.InitialDelaySeconds
Expand Down