Skip to content

Commit

Permalink
Add availability metrics (#453)
Browse files Browse the repository at this point in the history
* Add availability metrics

Signed-off-by: Maysun J Faisal <[email protected]>

* Add in availability test

Signed-off-by: Maysun J Faisal <[email protected]>

---------

Signed-off-by: Maysun J Faisal <[email protected]>
  • Loading branch information
maysunfaisal authored Mar 22, 2024
1 parent 77ecf15 commit 9adfc1d
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 1 deletion.
7 changes: 7 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import (
cdqanalysis "github.com/redhat-appstudio/application-service/cdq-analysis/pkg"
"github.com/redhat-appstudio/application-service/controllers"
"github.com/redhat-appstudio/application-service/controllers/webhooks"
"github.com/redhat-appstudio/application-service/pkg/availability"
"github.com/redhat-appstudio/application-service/pkg/github"
"github.com/redhat-appstudio/application-service/pkg/spi"
"github.com/redhat-appstudio/application-service/pkg/util/ioutils"
Expand Down Expand Up @@ -251,6 +252,12 @@ func main() {
os.Exit(1)
}

availabilityChecker := &availability.AvailabilityWatchdog{GitHubTokenClient: ghTokenClient}
if err := mgr.Add(availabilityChecker); err != nil {
setupLog.Error(err, "unable to set up availability checks")
os.Exit(1)
}

setupLog.Info("starting manager")
if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
Expand Down
71 changes: 71 additions & 0 deletions pkg/availability/git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// Copyright 2024 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package availability

import (
"context"
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/redhat-appstudio/application-service/pkg/github"
"github.com/redhat-appstudio/application-service/pkg/metrics"
ctrl "sigs.k8s.io/controller-runtime"
)

// Inspired from https://github.com/konflux-ci/remote-secret/blob/main/pkg/availability/storage_watchdog.go

type AvailabilityWatchdog struct {
GitHubTokenClient github.GitHubToken
}

func (r *AvailabilityWatchdog) Start(ctx context.Context) error {
// Check every 20 minutes
ticker := time.NewTicker(20 * time.Minute)
go func() {
for {
// make call immediately to avoid waiting for the first tick
r.checkAvailability(ctx)
select {
case <-ticker.C:
continue
case <-ctx.Done():
ticker.Stop()
return
}
}
}()
return nil
}

func (r *AvailabilityWatchdog) checkAvailability(ctx context.Context) {
log := ctrl.LoggerFrom(ctx)
checkGitLabel := prometheus.Labels{"check": "github"}

ghClient, err := r.GitHubTokenClient.GetNewGitHubClient("")
if err != nil {
log.Error(err, "Unable to create Go-GitHub client due to error, marking HAS availability as down")
metrics.HASAvailabilityGauge.With(checkGitLabel).Set(0)
}

isGitAvailable, err := ghClient.GetGitStatus(ctx)
if !isGitAvailable {
log.Error(err, "Unable to create Go-GitHub client due to error, marking HAS availability as down")
metrics.HASAvailabilityGauge.With(checkGitLabel).Set(0)
} else {
log.Info("HAS is marked as available, Git check has passed...")
metrics.HASAvailabilityGauge.With(checkGitLabel).Set(1)
}
}
41 changes: 41 additions & 0 deletions pkg/availability/git_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright 2024 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package availability

import (
"context"
"testing"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/redhat-appstudio/application-service/pkg/github"
"github.com/redhat-appstudio/application-service/pkg/metrics"
"github.com/stretchr/testify/assert"
)

func TestCheckAvailability(t *testing.T) {

t.Run("check availability", func(t *testing.T) {
checkGitLabel := prometheus.Labels{"check": "github"}
r := AvailabilityWatchdog{
GitHubTokenClient: github.MockGitHubTokenClient{},
}

r.checkAvailability(context.TODO())

assert.Equal(t, 1.0, testutil.ToFloat64(metrics.HASAvailabilityGauge.With(checkGitLabel)))
})
}
9 changes: 9 additions & 0 deletions pkg/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ func GetRepoAndOrgFromURL(repoURL string) (string, string, error) {
return repoName, orgName, nil
}

// GetGitStatus returns the status of the Git API with a simple noop call
func (g *GitHubClient) GetGitStatus(ctx context.Context) (bool, error) {
quote, response, err := g.Client.Zen(ctx)
if err == nil && response != nil && response.StatusCode >= 200 && response.StatusCode <= 299 && quote != "" {
return true, nil
}
return false, err
}

// GetDefaultBranchFromURL returns the default branch of a given repoURL
func (g *GitHubClient) GetDefaultBranchFromURL(repoURL string, ctx context.Context) (string, error) {
repoName, orgName, err := GetRepoAndOrgFromURL(repoURL)
Expand Down
35 changes: 35 additions & 0 deletions pkg/github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,41 @@ func TestGetRepoAndOrgFromURL(t *testing.T) {
}
}

func TestGetGitStatus(t *testing.T) {
tests := []struct {
name string
repoName string
orgName string
wantAvailable bool
wantErr bool
}{
{
name: "Simple repo name",
repoName: "test-repo-1",
orgName: "redhat-appstudio-appdata",
wantAvailable: true,
wantErr: false,
},
}

for _, tt := range tests {
mockedClient := GitHubClient{
Client: GetMockedClient(),
}

t.Run(tt.name, func(t *testing.T) {
isGitAvailable, err := mockedClient.GetGitStatus(context.Background())

if tt.wantErr != (err != nil) {
t.Errorf("TestGetGitStatus() unexpected error value: %v", err)
}
if !tt.wantErr && isGitAvailable != tt.wantAvailable {
t.Errorf("TestGetGitStatus() error: expected %v got %v", tt.wantAvailable, isGitAvailable)
}
})
}
}

func TestGetLatestCommitSHAFromRepository(t *testing.T) {
tests := []struct {
name string
Expand Down
7 changes: 7 additions & 0 deletions pkg/github/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ func GetMockedClient() *github.Client {
}
}),
),
mock.WithRequestMatchHandler(
mock.GetZen,
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
/* #nosec G104 -- test code */
w.Write([]byte("peace"))
}),
),
mock.WithRequestMatchHandler(
mock.GetReposByOwnerByRepo,
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Expand Down
9 changes: 9 additions & 0 deletions pkg/metrics/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,13 @@ var (
Help: "Number of successful import from git repository requests",
},
)

HASAvailabilityGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "has_availability",
Help: "Availability of the Konflux application service component",
},
// check - can have the values of "github" or whatever availability is being checked
[]string{"check"},
)
)
2 changes: 1 addition & 1 deletion pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
func init() {
// Register custom metrics with the global prometheus registry
metrics.Registry.MustRegister(GitOpsRepoCreationTotalReqs, GitOpsRepoCreationFailed, GitOpsRepoCreationSucceeded, ControllerGitRequest,
SecondaryRateLimitCounter, PrimaryRateLimitCounter, TokenPoolGauge,
SecondaryRateLimitCounter, PrimaryRateLimitCounter, TokenPoolGauge, HASAvailabilityGauge,
ApplicationDeletionTotalReqs, ApplicationDeletionSucceeded, ApplicationDeletionFailed,
ApplicationCreationSucceeded, ApplicationCreationFailed, ApplicationCreationTotalReqs,
componentCreationTotalReqs, componentCreationSucceeded, componentCreationFailed,
Expand Down

0 comments on commit 9adfc1d

Please sign in to comment.