Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into update_prom_op_crd
Browse files Browse the repository at this point in the history
  • Loading branch information
coleenquadros committed May 22, 2024
2 parents b02f5e3 + acbec98 commit 0274986
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,22 @@ import (
// +kubebuilder:validation:MaxLength=2083
type URL string

// Validate validates the underlying URL.
func (u URL) Validate() error {
_, err := url.Parse(string(u))
return err
}

// HostPath returns the URL's host together with its path.
// This also runs a validation of the underlying url.
func (u URL) HostPath() (string, error) {
parsedUrl, err := url.Parse(string(u))
if err != nil {
return "", err
}
return parsedUrl.Host + parsedUrl.Path, nil
}

// ObservabilityAddonSpec is the spec of observability addon.
type ObservabilityAddonSpec struct {
// EnableMetrics indicates the observability addon push metrics to hub server.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import (
func generateHubInfoSecret(client client.Client, obsNamespace string,
namespace string, ingressCtlCrdExists bool) (*corev1.Secret, error) {

obsApiRouteHost := ""
obsAPIHost := ""
alertmanagerEndpoint := ""
alertmanagerRouterCA := ""

if ingressCtlCrdExists {
var err error
obsApiRouteHost, err = config.GetObsAPIHost(context.TODO(), client, obsNamespace)
obsAPIHost, err = config.GetObsAPIExternalHost(context.TODO(), client, obsNamespace)
if err != nil {
log.Error(err, "Failed to get the host for observatorium API route")
log.Error(err, "Failed to get the host for Observatorium API host URL")
return nil, err
}

Expand All @@ -56,7 +56,7 @@ func generateHubInfoSecret(client client.Client, obsNamespace string,
} else {
// for KinD support, the managedcluster and hub cluster are assumed in the same cluster, the observatorium-api
// will be accessed through k8s service FQDN + port
obsApiRouteHost = config.GetOperandNamePrefix() + "observatorium-api" + "." + config.GetDefaultNamespace() + ".svc.cluster.local:8080"
obsAPIHost = config.GetOperandNamePrefix() + "observatorium-api" + "." + config.GetDefaultNamespace() + ".svc.cluster.local:8080"
// if alerting is disabled, do not set alertmanagerEndpoint
if !config.IsAlertingDisabled() {
alertmanagerEndpoint = config.AlertmanagerServiceName + "." + config.GetDefaultNamespace() + ".svc.cluster.local:9095"
Expand All @@ -70,7 +70,7 @@ func generateHubInfoSecret(client client.Client, obsNamespace string,
}

obsApiURL := url.URL{
Host: obsApiRouteHost,
Host: obsAPIHost,
Path: operatorconfig.ObservatoriumAPIRemoteWritePath,
}
if !obsApiURL.IsAbs() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

operatorv1 "github.com/openshift/api/operator/v1"
routev1 "github.com/openshift/api/route/v1"
mcoshared "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/shared"
mcov1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2"
"gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -120,10 +122,34 @@ func newTestAmDefaultCA() *corev1.ConfigMap {
}
}

func newMultiClusterObservability() *mcov1beta2.MultiClusterObservability {
return &mcov1beta2.MultiClusterObservability{
TypeMeta: metav1.TypeMeta{Kind: "MultiClusterObservability"},
ObjectMeta: metav1.ObjectMeta{Name: "test"},
Spec: mcov1beta2.MultiClusterObservabilitySpec{
StorageConfig: &mcov1beta2.StorageConfig{
MetricObjectStorage: &mcoshared.PreConfiguredStorage{
Key: "test",
Name: "test",
},
AlertmanagerStorageSize: "2Gi",
},
},
}
}

func TestNewSecret(t *testing.T) {
initSchema(t)

objs := []runtime.Object{newTestObsApiRoute(), newTestAlertmanagerRoute(), newTestIngressController(), newTestRouteCASecret()}
mco := newMultiClusterObservability()
config.SetMonitoringCRName(mco.Name)
objs := []runtime.Object{
newTestObsApiRoute(),
newTestAlertmanagerRoute(),
newTestIngressController(),
newTestRouteCASecret(),
mco,
}
c := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build()

hubInfo, err := generateHubInfoSecret(c, mcoNamespace, namespace, true)
Expand All @@ -138,6 +164,22 @@ func TestNewSecret(t *testing.T) {
if !strings.HasPrefix(hub.ObservatoriumAPIEndpoint, "https://test-host") || hub.AlertmanagerEndpoint != "https://"+routeHost || hub.AlertmanagerRouterCA != routerCA {
t.Fatalf("Wrong content in hub info secret: \ngot: "+hub.ObservatoriumAPIEndpoint+" "+hub.AlertmanagerEndpoint+" "+hub.AlertmanagerRouterCA, clusterName+" "+"https://test-host"+" "+"test-host"+" "+routerCA)
}

mco.Spec.AdvancedConfig = &mcov1beta2.AdvancedConfig{CustomObservabilityHubURL: "https://custom-obs", CustomAlertmanagerHubURL: "https://custom-am"}
c = fake.NewClientBuilder().WithRuntimeObjects(objs...).Build()
hubInfo, err = generateHubInfoSecret(c, mcoNamespace, namespace, true)
if err != nil {
t.Fatalf("Failed to initial the hub info secret: (%v)", err)
}
hub = &operatorconfig.HubInfo{}
err = yaml.Unmarshal(hubInfo.Data[operatorconfig.HubInfoSecretKey], &hub)
if err != nil {
t.Fatalf("Failed to unmarshal data in hub info secret (%v)", err)
}
if !strings.HasPrefix(hub.ObservatoriumAPIEndpoint, "https://custom-obs") || !strings.HasPrefix(hub.AlertmanagerEndpoint, "https://custom-am") || hub.AlertmanagerRouterCA != routerCA {
t.Fatalf("Wrong content in hub info secret: \ngot: "+hub.ObservatoriumAPIEndpoint+" "+hub.AlertmanagerEndpoint+" "+hub.AlertmanagerRouterCA, clusterName+" "+"https://custom-obs"+" "+"custom-obs"+" "+routerCA)
}

}

func TestNewBYOSecret(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ func pemEncode(cert []byte, key []byte) (*bytes.Buffer, *bytes.Buffer) {
func getHosts(c client.Client, ingressCtlCrdExists bool) ([]string, error) {
hosts := []string{config.GetObsAPISvc(config.GetOperandName(config.Observatorium))}
if ingressCtlCrdExists {
url, err := config.GetObsAPIHost(context.TODO(), c, config.GetDefaultNamespace())
url, err := config.GetObsAPIRouteHost(context.TODO(), c, config.GetDefaultNamespace())
if err != nil {
log.Error(err, "Failed to get api route address")
return nil, err
Expand Down
28 changes: 24 additions & 4 deletions operators/multiclusterobservability/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,23 @@ func GetDefaultTenantName() string {
return defaultTenantName
}

// GetObsAPIHost is used to get the URL for observartium api gateway.
func GetObsAPIHost(ctx context.Context, client client.Client, namespace string) (string, error) {
// GetObsAPIRouteHost is used to Route's host for Observatorium API. This doesn't take into consideration
// the `advanced.customObservabilityHubURL` configuration.
func GetObsAPIRouteHost(ctx context.Context, client client.Client, namespace string) (string, error) {
mco := &observabilityv1beta2.MultiClusterObservability{}
err := client.Get(ctx,
types.NamespacedName{
Name: GetMonitoringCRName(),
}, mco)
if err != nil && !errors.IsNotFound(err) {
return "", err
}
return GetRouteHost(client, obsAPIGateway, namespace)
}

// GetObsAPIExternalHost is used to get the frontend URL that should be used to reach the Observatorium API instance.
// This takes into consideration the `advanced.customObservabilityHubURL` configuration.
func GetObsAPIExternalHost(ctx context.Context, client client.Client, namespace string) (string, error) {
mco := &observabilityv1beta2.MultiClusterObservability{}
err := client.Get(ctx,
types.NamespacedName{
Expand All @@ -492,11 +507,16 @@ func GetObsAPIHost(ctx context.Context, client client.Client, namespace string)
}
advancedConfig := mco.Spec.AdvancedConfig
if advancedConfig != nil && advancedConfig.CustomObservabilityHubURL != "" {
err := advancedConfig.CustomObservabilityHubURL.Validate()
hubObsUrl := advancedConfig.CustomObservabilityHubURL
err := hubObsUrl.Validate()
if err != nil {
return "", err
}
obsHostPath, err := hubObsUrl.HostPath()
if err != nil {
return "", err
}
return string(advancedConfig.CustomObservabilityHubURL), nil
return obsHostPath, nil
}
return GetRouteHost(client, obsAPIGateway, namespace)
}
Expand Down
71 changes: 65 additions & 6 deletions operators/multiclusterobservability/pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
routev1 "github.com/openshift/api/route/v1"
fakeconfigclient "github.com/openshift/client-go/config/clientset/versioned/fake"
observatoriumv1alpha1 "github.com/stolostron/observatorium-operator/api/v1alpha1"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -252,7 +253,7 @@ func TestGetClusterIDFailed(t *testing.T) {
}
}

func TestGetObsAPIHost(t *testing.T) {
func TestGetObsAPIRouteHost(t *testing.T) {
route := &routev1.Route{
ObjectMeta: metav1.ObjectMeta{
Name: obsAPIGateway,
Expand All @@ -267,12 +268,14 @@ func TestGetObsAPIHost(t *testing.T) {
scheme.AddKnownTypes(mcov1beta2.GroupVersion, &mcov1beta2.MultiClusterObservability{})
client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route).Build()

host, _ := GetObsAPIHost(context.TODO(), client, "default")
host, err := GetObsAPIRouteHost(context.TODO(), client, "default")
assert.NoError(t, err)
if host == apiServerURL {
t.Errorf("Should not get route host in default namespace")
}

host, _ = GetObsAPIHost(context.TODO(), client, "test")
host, err = GetObsAPIRouteHost(context.TODO(), client, "test")
assert.NoError(t, err)
if host != apiServerURL {
t.Errorf("Observatorium api (%v) is not the expected (%v)", host, apiServerURL)
}
Expand All @@ -289,14 +292,70 @@ func TestGetObsAPIHost(t *testing.T) {
},
}
client = fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route, mco).Build()
host, _ = GetObsAPIHost(context.TODO(), client, "test")
if host != customBaseURL {
host, err = GetObsAPIRouteHost(context.TODO(), client, "test")
assert.NoError(t, err)
if host != apiServerURL {
t.Errorf("Observatorium api (%v) is not the expected (%v)", host, apiServerURL)
}

mco.Spec.AdvancedConfig.CustomObservabilityHubURL = "httpa://foob ar.c"
client = fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route, mco).Build()
host, err = GetObsAPIRouteHost(context.TODO(), client, "test")
assert.NoError(t, err)
if host != apiServerURL {
t.Errorf("Observatorium api (%v) is not the expected (%v)", host, apiServerURL)
}
}

func TestGetObsAPIExternalHost(t *testing.T) {
route := &routev1.Route{
ObjectMeta: metav1.ObjectMeta{
Name: obsAPIGateway,
Namespace: "test",
},
Spec: routev1.RouteSpec{
Host: apiServerURL,
},
}
scheme := runtime.NewScheme()
scheme.AddKnownTypes(routev1.GroupVersion, route)
scheme.AddKnownTypes(mcov1beta2.GroupVersion, &mcov1beta2.MultiClusterObservability{})
client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route).Build()

host, err := GetObsAPIExternalHost(context.TODO(), client, "default")
assert.NoError(t, err)
if host == apiServerURL {
t.Errorf("Should not get route host in default namespace")
}

host, err = GetObsAPIExternalHost(context.TODO(), client, "test")
assert.NoError(t, err)
if host != apiServerURL {
t.Errorf("Observatorium api (%v) is not the expected (%v)", host, apiServerURL)
}

customBaseURL := "https://custom.base/url"
expectedHost := "custom.base/url"
mco := &mcov1beta2.MultiClusterObservability{
ObjectMeta: metav1.ObjectMeta{
Name: GetMonitoringCRName(),
},
Spec: mcov1beta2.MultiClusterObservabilitySpec{
AdvancedConfig: &mcov1beta2.AdvancedConfig{
CustomObservabilityHubURL: mcoshared.URL(customBaseURL),
},
},
}
client = fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route, mco).Build()
host, err = GetObsAPIExternalHost(context.TODO(), client, "test")
assert.NoError(t, err)
if host != expectedHost {
t.Errorf("Observatorium api (%v) is not the expected (%v)", host, customBaseURL)
}

mco.Spec.AdvancedConfig.CustomObservabilityHubURL = "httpa://foob ar.c"
client = fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route, mco).Build()
_, err := GetObsAPIHost(context.TODO(), client, "test")
_, err = GetObsAPIExternalHost(context.TODO(), client, "test")
if err == nil {
t.Errorf("expected error when parsing URL '%v', but got none", mco.Spec.AdvancedConfig.CustomObservabilityHubURL)
}
Expand Down

0 comments on commit 0274986

Please sign in to comment.