diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c8abeeb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM golang:alpine AS builder + +WORKDIR /app +COPY . . + +RUN go build . +RUN mkdir workflows/ + +FROM scratch + +WORKDIR /app + +COPY conf/ocmonitor_conf.json /app/conf/ +COPY --from=builder /app/oc-monitor . +COPY --from=builder /app/workflows/ . + +ENTRYPOINT [ "/app/oc-monitor" ] diff --git a/README.md b/README.md index 1427fef..da10d88 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # oc-monitor +## Deploy in k8s (dev) + +While a registry with all of the OC docker images has not been set-up we can export this image to k3s ctr + +> docker save oc-monitor:latest | sudo k3s ctr images import - + +Then in the pod manifest for oc-monitor use : + +``` +image: docker.io/library/oc-monitor +imagePullPolicy: Never +``` + +Not doing so will end up in the pod having a `ErrorImagePull` \ No newline at end of file diff --git a/conf/conf.go b/conf/conf.go new file mode 100644 index 0000000..d2cd39b --- /dev/null +++ b/conf/conf.go @@ -0,0 +1,30 @@ +package conf + +import "sync" + +// declare the flag to use for each variable +var map_arguments = map[string]string { + "LokiURL" : "u", + "ArgoFile": "f", + "ContainerName" : "n", +} + +type Config struct { + LokiURL string + ArgoFile string + ContainerName string +} + +var instance *Config +var once sync.Once + +func GetConfig() *Config { + once.Do(func() { + instance = &Config{} + }) + return instance +} + +func GetConfFromArgs(argument string){ + +} \ No newline at end of file diff --git a/conf/ocmonitor_conf.json b/conf/ocmonitor_conf.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/conf/ocmonitor_conf.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/go.mod b/go.mod index 9d94596..bb4d20b 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,16 @@ module oc-monitor go 1.22.0 -require github.com/grafana/loki-client-go v0.0.0-20230116142646-e7494d0ef70c +require ( + cloud.o-forge.io/core/oc-lib v0.0.0-20240725103514-2891dc8a6819 + github.com/akamensky/argparse v1.4.0 + github.com/goraz/onion v0.1.3 + github.com/rs/zerolog v1.33.0 +) require ( - github.com/blang/semver v3.5.1+incompatible // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/smartystreets/goconvey v1.6.4 // indirect + golang.org/x/sys v0.22.0 // indirect ) diff --git a/main.go b/main.go index 7032da4..07e1599 100644 --- a/main.go +++ b/main.go @@ -2,24 +2,114 @@ package main import ( "log" - "os/exec" + "os" + + "oc-monitor/conf" + + "cloud.o-forge.io/core/oc-lib/logs" + "github.com/akamensky/argparse" + "github.com/goraz/onion" + "github.com/rs/zerolog" ) +var logger zerolog.Logger +var parser argparse.Parser + +const defaultConfigFile = "/etc/oc/ocmonitor_conf.json" +const localConfigFile = "./conf/ocmonitor_conf.json" + func main() { - // Initialize LokiLogger - lokiLogger := NewLokiLogger("http://localhost:3100/loki/api/v1/push") // Replace with your Loki URL + + // Test if monitor is launched outside (with parameters) or in a k8s environment (env variables sets) + if os.Getenv("KUBERNETES_SERVICE_HOST") == ""{ + // Not in a k8s environment, get conf from parameters + parser = *argparse.NewParser("oc-monitor","Launch the execution of a workflow given as a parameter and sends the produced logs to a loki database") + loadConfig(false, &parser) + } else { + // Executed in a k8s environment + loadConfig(true,nil) + } + + logger = logs.CreateLogger("oc-monitor", conf.GetConfig().LokiURL) + logger.Debug().Msg("Loki URL : " + conf.GetConfig().LokiURL) + logger.Debug().Msg("Filename : " + conf.GetConfig().ArgoFile) + logger.Debug().Msg("Container Name : " + conf.GetConfig().ContainerName) + + // Wait for the argo file to be copied to the pod + wf_found := false + for(!wf_found){ + if _, err := os.Stat("./workflows/" + conf.GetConfig().ArgoFile); err == nil { + wf_found = true + } + } + logger.Debug().Msg("Submitting the argo workflow : " + conf.GetConfig().ArgoFile) + // // Initialize LokiLogger + // lokiLogger := NewLokiLogger("http://localhost:3100/loki/api/v1/push") // Replace with your Loki URL // Run the Argo command - cmd := exec.Command("argo", "submit", "your-workflow.yaml") - output, err := cmd.CombinedOutput() - if err != nil { - log.Fatalf("failed to run Argo command: %v", err) - } + // cmd := exec.Command("argo", "submit", "your-workflow.yaml") + // output, err := cmd.CombinedOutput() + // if err != nil { + // log.Fatalf("failed to run Argo command: %v", err) + // } - // Send logs to Loki - if err := lokiLogger.Log(`{job="argo"}`, string(output)); err != nil { - log.Fatalf("failed to send logs to Loki: %v", err) - } + // logger.Info().Msg(string(output)) + // // Send logs to Loki + // if err := lokiLogger.Log(`{job="argo"}`, string(output)); err != nil { + // log.Fatalf("failed to send logs to Loki: %v", err) + // } log.Println("Logs sent to Loki successfully.") } + +func loadConfig(is_k8s bool, parser *argparse.Parser){ + + var o *onion.Onion + + logger = logs.CreateLogger("oc-monitor","") + configFile := "" + + l3 := onion.NewEnvLayerPrefix("_", "OCMONITOR") + l2, err := onion.NewFileLayer(defaultConfigFile, nil) + if err == nil { + logger.Info().Msg("Config file found : " + defaultConfigFile) + configFile = defaultConfigFile + } + l1, err := onion.NewFileLayer(localConfigFile, nil) + if err == nil { + logger.Info().Msg("Local config file found " + localConfigFile + ", overriding default file") + configFile = localConfigFile + } + if configFile == "" { + logger.Info().Msg("No config file found, using env") + o = onion.New(l3) + } else if l1 == nil && l2 == nil { + o = onion.New(l1, l2, l3) + } else if l1 == nil { + o = onion.New(l2, l3) + } else if l2 == nil { + o = onion.New(l1, l3) + } + + // These variables can only be retrieved in the onion + // Variables that don't depend on the environmen (from conf file), can be loaded after + if (is_k8s){ + // We can't use underscore in the env variable names because it's the delimitor with OCMONITOR too + conf.GetConfig().LokiURL = o.GetStringDefault("lokiurl", "http://127.0.0.1:3100") + conf.GetConfig().ArgoFile = o.GetString("argofile") + conf.GetConfig().ContainerName = o.GetString("containername") + } else{ + url := parser.String("u", "url", &argparse.Options{Required: true,Default: "http://127.0.0.1:3100"}) + conf.GetConfig().LokiURL = *url + file := parser.String("f", "file", &argparse.Options{Required: true}) + conf.GetConfig().ArgoFile = *file + name := parser.String("n", "name", &argparse.Options{Required: true}) + conf.GetConfig().ContainerName = *name + + err := parser.Parse(os.Args) + if err != nil { + logger.Fatal().Msg(parser.Usage(err)) + } + + } +} \ No newline at end of file