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

Prom chart sync #184

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
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
36 changes: 29 additions & 7 deletions chart-sync/App.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
package main

import (
"github.com/devtron-labs/chart-sync/internals"
"github.com/devtron-labs/chart-sync/pkg"
"github.com/go-pg/pg"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.uber.org/zap"
"net/http"
"strconv"
"time"
)

type App struct {
Logger *zap.SugaredLogger
db *pg.DB
syncService pkg.SyncService
Logger *zap.SugaredLogger
db *pg.DB
syncService pkg.SyncService
configuration *internals.Configuration
}

func NewApp(Logger *zap.SugaredLogger,
db *pg.DB,
syncService pkg.SyncService) *App {
syncService pkg.SyncService,
configuration *internals.Configuration) *App {
return &App{
Logger: Logger,
db: db,
syncService: syncService,
Logger: Logger,
db: db,
syncService: syncService,
configuration: configuration,
}
}

func (app *App) Start() {
// Set up the /metrics endpoint for Prometheus to scrape
http.Handle("/metrics", promhttp.Handler())
go func() {
// Then modify the line to:
err := http.ListenAndServe(":"+strconv.Itoa(app.configuration.PrometheusMatrixPort), nil)
if err != nil {
app.Logger.Errorw("error in starting prometheus server", "err", err)
}
}()

// Start the sync service
_, err := app.syncService.Sync()
// sleep for ShutDownInterval seconds to give time for prometheus to scrape the metrics
time.Sleep(time.Duration(app.configuration.AppSyncJobShutDownInterval) * time.Second)

if err != nil {
app.Logger.Errorw("err", "err", err)
}
Expand Down
2 changes: 1 addition & 1 deletion chart-sync/env_gen.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"Category":"DEVTRON","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_STORE_APPLICATION_VERSIONS_SAVE_CHUNK_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CHART_PROVIDER_ID","EnvType":"string","EnvValue":"*","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IS_OCI_REGISTRY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"password","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"user","EnvDescription":"","Example":"","Deprecated":"false"}]}]
[{"Category":"DEVTRON","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_STORE_APPLICATION_VERSIONS_SAVE_CHUNK_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SHUTDOWN_INTERVAL","EnvType":"int","EnvValue":"60","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CHART_PROVIDER_ID","EnvType":"string","EnvValue":"*","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IS_OCI_REGISTRY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"password","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"user","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROMETHEUS_MATRIX_PORT","EnvType":"int","EnvValue":"8080","EnvDescription":"","Example":"","Deprecated":"false"}]}]
2 changes: 2 additions & 0 deletions chart-sync/env_gen.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
|-------|----------|-------------------|-------------------|-----------------------|------------------|
| APP | string |chart-sync | | | false |
| APP_STORE_APPLICATION_VERSIONS_SAVE_CHUNK_SIZE | int |20 | | | false |
| APP_SYNC_SHUTDOWN_INTERVAL | int |60 | | | false |
| CHART_PROVIDER_ID | string |* | | | false |
| IS_OCI_REGISTRY | bool |true | | | false |
| LOG_LEVEL | int |0 | | | false |
Expand All @@ -19,4 +20,5 @@
| PG_PORT | string |5432 | | | false |
| PG_QUERY_DUR_THRESHOLD | int64 |5000 | | | false |
| PG_USER | string |user | | | false |
| PROMETHEUS_MATRIX_PORT | int |8080 | | | false |

2 changes: 2 additions & 0 deletions chart-sync/internals/Configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type Configuration struct {
ChartProviderId string `env:"CHART_PROVIDER_ID" envDefault:"*"` // * is used to sync all chart providers; else CHART_PROVIDER_ID should contain chart_repo_id OR docker_artifact_store_id
IsOCIRegistry bool `env:"IS_OCI_REGISTRY" envDefault:"true"`
ParallelismLimitForTagProcessing int `env:"PARALLELISM_LIMIT_FOR_TAG_PROCESSING" envDefault:"0"`
AppSyncJobShutDownInterval int `env:"APP_SYNC_SHUTDOWN_INTERVAL" envDefault:"60"`
PrometheusMatrixPort int `env:"PROMETHEUS_MATRIX_PORT" envDefault:"8080"`
}

func ParseConfiguration() (*Configuration, error) {
Expand Down
69 changes: 69 additions & 0 deletions chart-sync/internals/instruments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package internals

import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)

var constLabels = map[string]string{"app": "chart-sync"}

// Counter metrics
var (
SyncRepo = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "sync_repo",
Help: "Number of standard repository sync operations",
ConstLabels: constLabels,
},
[]string{"repo_type", "repo_name"})

RepoSyncErrors = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "repo_sync_errors_total",
Help: "Total number of repository sync errors",
ConstLabels: constLabels,
},
[]string{"repo_type", "error_type"})

ChartVersionsProcessed = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "chart_versions_processed_total",
Help: "Total number of chart versions processed successfully",
ConstLabels: constLabels,
},
[]string{"repo_type", "chart_name"})

ChartVersionsFailedProcessing = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "chart_versions_failed_processing_total",
Help: "Total number of chart versions that failed processing",
ConstLabels: constLabels,
},
[]string{"repo_type", "chart_name", "error_type"})

AppStoresCreated = promauto.NewCounter(
prometheus.CounterOpts{
Name: "app_stores_created_total",
Help: "Total number of app stores created during sync",
ConstLabels: constLabels,
})

AppVersionsCreated = promauto.NewCounter(
prometheus.CounterOpts{
Name: "app_versions_created_total",
Help: "Total number of app versions created during sync",
ConstLabels: constLabels,
})
)

// Histogram metrics
var (
RepoSyncDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "repo_sync_duration_seconds",
Help: "Time taken to sync an entire repository",
ConstLabels: constLabels,
Buckets: prometheus.DefBuckets,
},
[]string{"repo_type", "repo_name"})
)
39 changes: 39 additions & 0 deletions chart-sync/pkg/SyncService.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ func (impl *SyncServiceImpl) Sync() (interface{}, error) {
ociRegistries []*sql.DockerArtifactStore
ociRegistry *sql.DockerArtifactStore
)
// Track overall sync time
start := time.Now()
defer func() {
internals.RepoSyncDuration.WithLabelValues("all", "all").Observe(time.Since(start).Seconds())
}()
if impl.configuration.ChartProviderId == "*" {
ociRegistries, err = impl.dockerArtifactStoreRepository.FindAllChartProviders()
if err != nil {
Expand Down Expand Up @@ -134,6 +139,15 @@ func extractChartRepoRepositoryList(repositoryList string) []string {
}

func (impl *SyncServiceImpl) syncOCIRepo(ociRepo *sql.DockerArtifactStore) error {
// Track OCI repo sync time
start := time.Now()
defer func() {
internals.RepoSyncDuration.WithLabelValues("oci", ociRepo.RegistryURL).Observe(time.Since(start).Seconds())
}()

// prometheus event for OCI registry sync (already present)
internals.SyncRepo.WithLabelValues("oci", ociRepo.RegistryURL).Inc()

applications, err := impl.appStoreRepository.FindByStoreId(ociRepo.Id)
if err != nil {
impl.logger.Errorw("error in fetching app for repo", "OCI registry", ociRepo.Id, "err", err)
Expand Down Expand Up @@ -236,6 +250,8 @@ func (impl *SyncServiceImpl) syncOCIRepo(ociRepo *sql.DockerArtifactStore) error
impl.logger.Errorw("error in saving app", "app", app, "err", err)
continue
}
// Increment app stores created counter
internals.AppStoresCreated.Inc()
} else {
continue
}
Expand All @@ -250,6 +266,7 @@ func (impl *SyncServiceImpl) syncOCIRepo(ociRepo *sql.DockerArtifactStore) error
err = impl.updateOCIRegistryChartVersionsV2(client, id, chartVersions, ociRepo, chartName)
}
if err != nil {
internals.RepoSyncErrors.WithLabelValues("oci", "process_error").Inc()
impl.logger.Errorw("error in updating chart versions", "err", err, "appId", id)
continue
}
Expand All @@ -258,6 +275,15 @@ func (impl *SyncServiceImpl) syncOCIRepo(ociRepo *sql.DockerArtifactStore) error
}

func (impl *SyncServiceImpl) syncRepo(repo *sql.ChartRepo) error {
// Track standard repo sync time
start := time.Now()
defer func() {
internals.RepoSyncDuration.WithLabelValues("standard", repo.Name).Observe(time.Since(start).Seconds())
}()

// prometheus event for registry sync (already present)
internals.SyncRepo.WithLabelValues("standard", repo.Name).Inc()

indexFile, err := impl.helmRepoManager.LoadIndexFile(repo)
if err != nil {
impl.logger.Errorw("error in loading index file", "repo", repo.Name, "err", err)
Expand Down Expand Up @@ -288,13 +314,17 @@ func (impl *SyncServiceImpl) syncRepo(repo *sql.ChartRepo) error {
impl.logger.Errorw("error in saving app", "app", app, "err", err)
continue
}
// Increment app stores created counter
internals.AppStoresCreated.Inc()

applicationId[name] = app.Id
id = app.Id
}
//update entries if any id, chartVersions
impl.logger.Infow("handling all versions of chart", "repoName", repo.Name, "chartName", name, "chartVersions", len(chartVersions))
err := impl.updateChartVersions(id, &chartVersions, repo.Url, repo.Username, repo.Password, repo.AllowInsecureConnection)
if err != nil {
internals.RepoSyncErrors.WithLabelValues("standard", "process_error").Inc()
impl.logger.Errorw("error in updating chart versions", "err", err, "appId", id)
continue
}
Expand Down Expand Up @@ -385,6 +415,8 @@ func (impl *SyncServiceImpl) updateChartVersions(appId int, chartVersions *repo.
impl.logger.Errorw("error in updating", "totalIn", len(*chartVersions), "totalOut", len(appVersions), "err", err)
return err
}
// Count app versions created
internals.AppVersionsCreated.Add(float64(len(appVersions)))
// reset the array
appVersions = nil
}
Expand All @@ -397,6 +429,9 @@ func (impl *SyncServiceImpl) updateChartVersions(appId int, chartVersions *repo.

// if any version left to save
if len(appVersions) > 0 {
// Count app versions created
internals.AppVersionsCreated.Add(float64(len(appVersions)))

impl.logger.Infow("saving remaining chart versions into DB", "versions", len(appVersions))
err = impl.appStoreApplicationVersionRepository.Save(&appVersions)
if err != nil {
Expand Down Expand Up @@ -424,10 +459,14 @@ func (impl *SyncServiceImpl) updateOCIRegistryChartVersions(client *registry.Cli

chartData, err := impl.helmRepoManager.OCIRepoValuesJson(client, ociRepo.RegistryURL, chartName, chartVersion)
if err != nil {
internals.ChartVersionsFailedProcessing.WithLabelValues("oci", chartName, "processing_error").Inc()
impl.logger.Errorw("error in getting values yaml", "err", err)
continue
}

// Track successful processing
internals.ChartVersionsProcessed.WithLabelValues("oci", chartName).Inc()

if !isAnyChartVersionFound {
isAnyChartVersionFound = true
}
Expand Down
2 changes: 1 addition & 1 deletion chart-sync/wire_gen.go

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

Loading