diff --git a/Dockerfile b/Dockerfile index f0cb4df..ae74d40 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,15 @@ FROM golang:alpine AS builder WORKDIR /app + COPY . . + RUN go build . -FROM argoproj/argocd:latest +RUN ls /app + +FROM scratch WORKDIR /app -COPY conf/docker_ocmonitord_conf.json /app/conf/ COPY --from=builder /app/oc-monitord . \ No newline at end of file diff --git a/conf/conf.go b/conf/conf.go index 3de8b82..860605b 100644 --- a/conf/conf.go +++ b/conf/conf.go @@ -3,14 +3,21 @@ package conf import "sync" type Config struct { - MongoURL string - Database string + MongoURL string + Database string LokiURL string - NatsURL string + NatsURL string ExecutionID string + PeerID string Timeout int WorkflowID string - Logs string + Logs string + Mode string + KubeHost string + KubePort string + KubeCA string + KubeCert string + KubeData string } var instance *Config diff --git a/docker_schedulerd.json b/docker_schedulerd.json new file mode 100644 index 0000000..853922f --- /dev/null +++ b/docker_schedulerd.json @@ -0,0 +1,5 @@ +{ + "MONGO_URL":"mongodb://mongo:27017/", + "NATS_URL":"nats://nats:4222", + "MONGO_DATABASE":"DC_myDC" +} \ No newline at end of file diff --git a/go.mod b/go.mod index 47aafe4..0a1460e 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,11 @@ module oc-monitord -go 1.22.0 +go 1.23.1 -toolchain go1.22.4 +toolchain go1.23.3 require ( - cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418 - github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d + cloud.o-forge.io/core/oc-lib v0.0.0-20250213085018-271cc2caa026 github.com/akamensky/argparse v1.4.0 github.com/google/uuid v1.6.0 github.com/goraz/onion v0.1.3 @@ -17,40 +16,86 @@ require ( require ( github.com/beego/beego/v2 v2.3.1 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/grpc v1.63.0 // indirect +) + +require ( + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d + github.com/argoproj/argo-workflows/v3 v3.6.4 github.com/beorn7/perks v1.0.1 // indirect + github.com/biter777/countries v1.7.5 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nats.go v1.37.0 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.19.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/robfig/cron v1.2.0 // indirect github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect github.com/ugorji/go/codec v1.1.7 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect go.mongodb.org/mongo-driver v1.17.1 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.7.0 // indirect google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/api v0.32.1 + k8s.io/apimachinery v0.32.1 + k8s.io/client-go v0.32.1 + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 9555143..2a70151 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,27 @@ -cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418 h1:24nc5qA6AkV6pIbJJeRASeUZmWuGkl+FO/r2oXazJ8w= -cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.o-forge.io/core/oc-lib v0.0.0-20250213085018-271cc2caa026 h1:CYwpofGfpAhMDrT6jqvu9NI/tcgxCD8PKJZDKEfTvVI= +cloud.o-forge.io/core/oc-lib v0.0.0-20250213085018-271cc2caa026/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc= github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/argoproj/argo-workflows/v3 v3.6.4 h1:5+Cc1UwaQE5ka3w7R3hxZ1TK3M6VjDEXA5WSQ/IXrxY= +github.com/argoproj/argo-workflows/v3 v3.6.4/go.mod h1:2f5zB8CkbNCCO1od+kd1dWkVokqcuyvu+tc+Jwx1MZg= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beego/beego/v2 v2.3.1 h1:7MUKMpJYzOXtCUsTEoXOxsDV/UcHw6CPbaWMlthVNsc= github.com/beego/beego/v2 v2.3.1/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/biter777/countries v1.7.5 h1:MJ+n3+rSxWQdqVJU8eBy9RqcdH6ePPn4PJHocVWUa+Q= +github.com/biter777/countries v1.7.5/go.mod h1:1HSpZ526mYqKJcpT5Ti1kcGQ0L0SrXWIaptUWjFfv2E= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -20,52 +30,101 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/etcd v3.3.17+incompatible/go.mod h1:cdZ77EstHBwVtD6iTgzgvogwcjo9m4iOqoijouPJ4bs= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= -github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/goraz/onion v0.1.3 h1:KhyvbDA2b70gcz/d5izfwTiOH8SmrvV43AsVzpng3n0= github.com/goraz/onion v0.1.3/go.mod h1:XEmz1XoBz+wxTgWB8NwuvRm4RAu3vKxvrmYtzK+XCuQ= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -77,11 +136,16 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= @@ -91,29 +155,40 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/nwtgck/go-fakelish v0.1.3 h1:bA8/xa9hQmzppexIhBvdmztcd/PJ4SPuAUTBdMKZ8G4= github.com/nwtgck/go-fakelish v0.1.3/go.mod h1:2HC44/OwVWwOa/g3+P2jUM3FEHQ0ya4gyCSU19PPd3Y= github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik= github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skarademir/naturalsort v0.0.0-20150715044055-69a5d87bef62/go.mod h1:oIdVclZaltY1Nf7OQUkg1/2jImBJ+ZfKZuDIRSwk3p0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -125,16 +200,21 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -144,60 +224,149 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM= go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= +k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= +k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= +k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= +k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/main.go b/main.go index 52ec8ec..46f0513 100644 --- a/main.go +++ b/main.go @@ -2,25 +2,32 @@ package main import ( "bufio" + "encoding/base64" "encoding/json" "fmt" "io" "os" "os/exec" "regexp" - "strconv" + "slices" "strings" "sync" "oc-monitord/conf" "oc-monitord/models" + u "oc-monitord/utils" "oc-monitord/workflow_builder" oclib "cloud.o-forge.io/core/oc-lib" "cloud.o-forge.io/core/oc-lib/logs" + "cloud.o-forge.io/core/oc-lib/models/booking" + "cloud.o-forge.io/core/oc-lib/models/peer" "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/models/workflow_execution" + "cloud.o-forge.io/core/oc-lib/tools" + + tools2 "oc-monitord/tools" "github.com/akamensky/argparse" "github.com/google/uuid" @@ -38,7 +45,6 @@ import ( var logger zerolog.Logger var wf_logger zerolog.Logger var parser argparse.Parser -var monitorLocal bool var workflowName string const defaultConfigFile = "/etc/oc/ocmonitord_conf.json" @@ -47,20 +53,8 @@ const localConfigFile = "./conf/local_ocmonitord_conf.json" func main() { os.Setenv("test_service", "true") // Only for service demo, delete before merging on main - - monitorLocal = false - // 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 - fmt.Println("Executes outside of k8s") - parser = *argparse.NewParser("oc-monitord", "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 - fmt.Println("Executes inside a k8s") - monitorLocal = true - loadConfig(true, nil) - } + parser = *argparse.NewParser("oc-monitord", "Launch the execution of a workflow given as a parameter and sends the produced logs to a loki database") + loadConfig(false, &parser) oclib.InitDaemon("oc-monitord") oclib.SetConfig( @@ -75,11 +69,10 @@ func main() { logger.Debug().Msg("Loki URL : " + conf.GetConfig().LokiURL) logger.Debug().Msg("Workflow executed : " + conf.GetConfig().ExecutionID) + exec := u.GetExecution(conf.GetConfig().ExecutionID) + conf.GetConfig().WorkflowID = exec.WorkflowID - wf_id := getWorkflowId(conf.GetConfig().ExecutionID) - conf.GetConfig().WorkflowID = wf_id - - logger.Debug().Msg("Starting construction of yaml argo for workflow :" + wf_id) + logger.Debug().Msg("Starting construction of yaml argo for workflow :" + exec.WorkflowID) if _, err := os.Stat("./argo_workflows/"); os.IsNotExist(err) { os.Mkdir("./argo_workflows/", 0755) @@ -89,12 +82,12 @@ func main() { // // create argo new_wf := workflow_builder.WorflowDB{} - err := new_wf.LoadFrom(conf.GetConfig().WorkflowID) + err := new_wf.LoadFrom(conf.GetConfig().WorkflowID, conf.GetConfig().PeerID) if err != nil { logger.Error().Msg("Could not retrieve workflow " + conf.GetConfig().WorkflowID + " from oc-catalog API") } - argo_file_path, stepMax, err := new_wf.ExportToArgo(conf.GetConfig().Timeout) + argo_file_path, stepMax, err := new_wf.ExportToArgo(exec.ExecutionsID, conf.GetConfig().Timeout) if err != nil { logger.Error().Msg("Could not create the Argo file for " + conf.GetConfig().WorkflowID) logger.Error().Msg(err.Error()) @@ -106,31 +99,44 @@ func main() { wf_logger = logger.With().Str("argo_name", workflowName).Str("workflow_id", conf.GetConfig().WorkflowID).Str("workflow_execution_id", conf.GetConfig().ExecutionID).Logger() wf_logger.Debug().Msg("Testing argo name") - executeWorkflow(argo_file_path, stepMax) - -} - -// Return the Workflow ID associated to a workflow execution object -func getWorkflowId(exec_id string) string { - res := oclib.LoadOne(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), exec_id) - if res.Code != 200 { - logger.Error().Msg("Could not retrieve workflow ID from execution ID " + exec_id) - return "" + if conf.GetConfig().KubeHost == "" { + // Not in a k8s environment, get conf from parameters + fmt.Println("Executes outside of k8s") + executeOutside(argo_file_path, stepMax) + } else { + // Executed in a k8s environment + fmt.Println("Executes inside a k8s") + executeInside(exec.GetID(), "argo", argo_file_path, stepMax) } - wf_exec := res.ToWorkflowExecution() - - return wf_exec.WorkflowID } // So far we only log the output from +func executeInside(execID string, ns string, argo_file_path string, stepMax int) { + t, err := tools2.NewService(conf.GetConfig().Mode) + if err != nil { + logger.Error().Msg("Could not create KubernetesTool") + } + name, err := t.CreateArgoWorkflow(argo_file_path, ns) + if err != nil { + logger.Error().Msg("Could not create argo workflow : " + err.Error()) + } else { + split := strings.Split(argo_file_path, "_") + argoLogs := models.NewArgoLogs(split[0], "argo", stepMax) + argoLogs.StartStepRecording(argoLogs.NewWatch(), wf_logger) + err := t.LogWorkflow(execID, ns, name, argo_file_path, stepMax, argoLogs.NewWatch(), argoLogs.NewWatch(), argoLogs, []string{}, logWorkflow) + if err != nil { + logger.Error().Msg("Could not log workflow : " + err.Error()) + } + } -func executeWorkflow(argo_file_path string, stepMax int) { +} + +func executeOutside(argo_file_path string, stepMax int) { // var stdout, stderr, stdout_logs, stderr_logs io.ReadCloser var stdout, stderr io.ReadCloser // var stderr io.ReadCloser var err error - cmd := exec.Command("argo", "submit", "--log", "./argo_workflows/"+argo_file_path, "--serviceaccount=argo", "-n", "argo") - fmt.Println(cmd) + cmd := exec.Command("argo", "submit", "--log", argo_file_path, "--serviceaccount=argo", "-n", "argo") if stdout, err = cmd.StdoutPipe(); err != nil { wf_logger.Error().Msg("Could not retrieve stdoutpipe " + err.Error()) return @@ -139,38 +145,65 @@ func executeWorkflow(argo_file_path string, stepMax int) { panic(err) } var wg sync.WaitGroup - go logWorkflow(argo_file_path, stepMax, stdout, &wg) + split := strings.Split(argo_file_path, "_") + argoLogs := models.NewArgoLogs(split[0], "argo", stepMax) + argoLogs.StartStepRecording(argoLogs.NewWatch(), wf_logger) + argoLogs.IsStreaming = true + go logWorkflow(argo_file_path, stepMax, stdout, argoLogs.NewWatch(), argoLogs.NewWatch(), argoLogs, []string{}, &wg) if err := cmd.Wait(); err != nil { wf_logger.Error().Msg("Could not execute argo submit") wf_logger.Error().Msg(err.Error() + bufio.NewScanner(stderr).Text()) - updateStatus("fatal") + updateStatus("fatal", "") } - wg.Wait() } // We could improve this function by creating an object with the same attribute as the output // and only send a new log if the current object has different values than the previous -func logWorkflow(argo_file_path string, stepMax int, pipe io.ReadCloser, wg *sync.WaitGroup) { - var current_watch, previous_watch *models.ArgoWatch - split := strings.Split(argo_file_path, "_") - argoLogs := models.NewArgoLogs(split[0], "argo", stepMax) - - watch_output := make([]string, 0) +func logWorkflow(argo_file_path string, stepMax int, pipe io.ReadCloser, + current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, + argoLogs *models.ArgoLogs, seen []string, wg *sync.WaitGroup) { scanner := bufio.NewScanner(pipe) + count := 0 + see := "" + seeit := 0 for scanner.Scan() { log := scanner.Text() - watch_output = append(watch_output, log) - if strings.Contains(log, "Progress:") { - current_watch = argoLogs.StopStepRecording(watch_output) - watch_output = []string{} - } else if strings.Contains(log, "sub-process exited") { - current_watch = argoLogs.StopStepRecording(watch_output) + if strings.Contains(log, "capturing logs") && count == 0 { + if !argoLogs.IsStreaming { + wg.Add(1) + } + seeit++ + } else if count == 0 { + if argoLogs.IsStreaming { + continue + } else { + break + } } - if current_watch != nil && !current_watch.Equals(previous_watch) && current_watch.Name != "" { - wg.Add(1) - checkStatus(current_watch, previous_watch) + if count == 1 { + see = log + if slices.Contains(argoLogs.Seen, see) && !argoLogs.IsStreaming { + wg.Done() + seeit-- + break + } + } + if !slices.Contains(current_watch.Logs, log) { + current_watch.Logs = append(current_watch.Logs, log) + } + count++ + if strings.Contains(log, "sub-process exited") { + current_watch = argoLogs.StopStepRecording(current_watch) + argoLogs.Seen = append(argoLogs.Seen, see) + if checkStatus(current_watch, previous_watch, argoLogs) { + count = 0 + if !argoLogs.IsStreaming { + wg.Done() + } + seeit-- + } jsonified, err := json.Marshal(current_watch) if err != nil { logger.Error().Msg("Could not create watch log") @@ -182,20 +215,13 @@ func logWorkflow(argo_file_path string, stepMax int, pipe io.ReadCloser, wg *syn } previous_watch = current_watch current_watch = &models.ArgoWatch{} - watch_output = []string{} - wg.Done() } } } func loadConfig(is_k8s bool, parser *argparse.Parser) { - var o *onion.Onion - o = initOnion(o) - // These variables can only be retrieved in the onion - // Variables that don't depend on the environment (from conf file), can be loaded after - // We can't use underscore in the env variable names because it's the delimitor with OCMONITOR too setConf(is_k8s, o, parser) if !IsValidUUID(conf.GetConfig().ExecutionID) { @@ -204,41 +230,50 @@ func loadConfig(is_k8s bool, parser *argparse.Parser) { } func setConf(is_k8s bool, o *onion.Onion, parser *argparse.Parser) { - if is_k8s { - conf.GetConfig().LokiURL = o.GetStringDefault("lokiurl", "http://127.0.0.1:3100") - i, err := strconv.Atoi(o.GetString("timeout")) - if err == nil { - conf.GetConfig().Timeout = i - } else { - logger.Error().Msg("Could not parse timeout, using default value") - } - conf.GetConfig().ExecutionID = o.GetString("workflow") - mongo := o.GetStringDefault("mongourl", "mongodb://127.0.0.1:27017") - db := o.GetStringDefault("database", "DC_myDC") + url := parser.String("u", "url", &argparse.Options{Required: true, Default: "http://127.0.0.1:3100", Help: "Url to the Loki database logs will be sent to"}) + mode := parser.String("M", "mode", &argparse.Options{Required: false, Default: "", Help: "Mode of the execution"}) + execution := parser.String("e", "execution", &argparse.Options{Required: true, Help: "Execution ID of the workflow to request from oc-catalog API"}) + peer := parser.String("p", "peer", &argparse.Options{Required: false, Default: "", Help: "Peer ID of the workflow to request from oc-catalog API"}) + mongo := parser.String("m", "mongo", &argparse.Options{Required: true, Default: "mongodb://127.0.0.1:27017", Help: "URL to reach the MongoDB"}) + db := parser.String("d", "database", &argparse.Options{Required: true, Default: "DC_myDC", Help: "Name of the database to query in MongoDB"}) + timeout := parser.Int("t", "timeout", &argparse.Options{Required: false, Default: -1, Help: "Timeout for the execution of the workflow"}) - conf.GetConfig().MongoURL = mongo - conf.GetConfig().Database = db - } else { - url := parser.String("u", "url", &argparse.Options{Required: true, Default: "http://127.0.0.1:3100", Help: "Url to the Loki database logs will be sent to"}) - execution := parser.String("e", "execution", &argparse.Options{Required: true, Help: "Execution ID of the workflow to request from oc-catalog API"}) - mongo := parser.String("m", "mongo", &argparse.Options{Required: true, Default: "mongodb://127.0.0.1:27017", Help: "URL to reach the MongoDB"}) - db := parser.String("d", "database", &argparse.Options{Required: true, Default: "DC_myDC", Help: "Name of the database to query in MongoDB"}) - timeout := parser.Int("t", "timeout", &argparse.Options{Required: false, Default: -1, Help: "Timeout for the execution of the workflow"}) - err := parser.Parse(os.Args) - if err != nil { - fmt.Println(parser.Usage(err)) - os.Exit(1) - } + ca := parser.String("c", "ca", &argparse.Options{Required: false, Default: "", Help: "CA file for the Kubernetes cluster"}) + cert := parser.String("C", "cert", &argparse.Options{Required: false, Default: "", Help: "Cert file for the Kubernetes cluster"}) + data := parser.String("D", "data", &argparse.Options{Required: false, Default: "", Help: "Data file for the Kubernetes cluster"}) - conf.GetConfig().Logs = "debug" + host := parser.String("H", "host", &argparse.Options{Required: false, Default: "", Help: "Host for the Kubernetes cluster"}) + port := parser.String("P", "port", &argparse.Options{Required: false, Default: "6443", Help: "Port for the Kubernetes cluster"}) - conf.GetConfig().LokiURL = *url - conf.GetConfig().MongoURL = *mongo - conf.GetConfig().Database = *db - conf.GetConfig().Timeout = *timeout - conf.GetConfig().ExecutionID = *execution + err := parser.Parse(os.Args) + if err != nil { + fmt.Println(parser.Usage(err)) + os.Exit(1) } + conf.GetConfig().Logs = "debug" + conf.GetConfig().LokiURL = *url + conf.GetConfig().MongoURL = *mongo + conf.GetConfig().Database = *db + conf.GetConfig().Timeout = *timeout + conf.GetConfig().Mode = *mode + conf.GetConfig().ExecutionID = *execution + conf.GetConfig().PeerID = *peer + conf.GetConfig().KubeHost = *host + conf.GetConfig().KubePort = *port + + decoded, err := base64.StdEncoding.DecodeString(*ca) + if err == nil { + conf.GetConfig().KubeCA = string(decoded) + } + decoded, err = base64.StdEncoding.DecodeString(*cert) + if err == nil { + conf.GetConfig().KubeCert = string(decoded) + } + decoded, err = base64.StdEncoding.DecodeString(*data) + if err == nil { + conf.GetConfig().KubeData = string(decoded) + } } func initOnion(o *onion.Onion) *onion.Onion { @@ -283,23 +318,62 @@ func getContainerName(argo_file string) string { } // Uses the ArgoWatch object to update status of the workflow execution object -func checkStatus(current *models.ArgoWatch, previous *models.ArgoWatch) { - if previous != nil && current.Status != previous.Status { - updateStatus(current.Status) +func checkStatus(current *models.ArgoWatch, previous *models.ArgoWatch, argoLogs *models.ArgoLogs) bool { + if previous == nil || current.Status != previous.Status || argoLogs.IsStreaming { + argoLogs.StepCount += 1 + if len(current.Logs) > 0 { + newLogs := []string{} + for _, log := range current.Logs { + if !slices.Contains(argoLogs.Logs, log) { + newLogs = append(newLogs, log) + } + } + updateStatus(current.Status, strings.Join(newLogs, "\n")) + current.Logs = newLogs + argoLogs.Logs = append(argoLogs.Logs, newLogs...) + } else { + updateStatus(current.Status, "") + } } + return previous == nil || current.Status != previous.Status || argoLogs.IsStreaming } -func updateStatus(status string) { +func updateStatus(status string, log string) { exec_id := conf.GetConfig().ExecutionID wf_exec := &workflow_execution.WorkflowExecution{AbstractObject: utils.AbstractObject{UUID: conf.GetConfig().ExecutionID}} wf_exec.ArgoStatusToState(status) - - serialized := wf_exec.Serialize() - - res := oclib.UpdateOne(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), serialized, exec_id) - - if res.Code != 200 { - logger.Error().Msg("Could not update status for workflow execution " + exec_id) + exec, _, err := workflow_execution.NewAccessor(&tools.APIRequest{ + PeerID: conf.GetConfig().PeerID, + }).UpdateOne(wf_exec, exec_id) + if err != nil { + logger.Error().Msg("Could not update status for workflow execution " + exec_id + err.Error()) + } + splitted := strings.Split(log, "-") + if len(splitted) > 1 { + we := exec.(*workflow_execution.WorkflowExecution) + itemID := splitted[len(splitted)-1] // TODO: in logs found item ID + caller := &tools.HTTPCaller{ + URLS: map[tools.DataType]map[tools.METHOD]string{ + tools.PEER: { + tools.POST: "/status/", + }, + tools.BOOKING: { + tools.PUT: "http://localhost:8080/booking/:id", + }, + }, + } + if we.PeerBookByGraph != nil { + for peerID, val := range we.PeerBookByGraph { + if val[itemID] == nil { + continue + } + for _, log := range val[itemID] { + (&peer.Peer{}).LaunchPeerExecution(peerID, log, tools.BOOKING, tools.PUT, &booking.Booking{ + State: we.State, + }, caller) + } + } + } } } diff --git a/models/argo_logs.go b/models/argo_logs.go index 534adac..1796813 100644 --- a/models/argo_logs.go +++ b/models/argo_logs.go @@ -1,12 +1,14 @@ package models import ( + "encoding/json" "fmt" "strconv" "strings" "time" "github.com/acarl005/stripansi" + "github.com/rs/zerolog" ) type ArgoWatch struct { @@ -41,6 +43,7 @@ func NewArgoLogs(name string, namespace string, stepMax int) *ArgoLogs { StepCount: 0, StepMax: stepMax, stop: false, + Seen: []string{}, } } @@ -52,19 +55,42 @@ type ArgoLogs struct { StepMax int stop bool Started time.Time + Seen []string + Logs []string + IsStreaming bool } -func (a *ArgoLogs) StartStepRecording() { +func (a *ArgoLogs) NewWatch() *ArgoWatch { + return &ArgoWatch{ + Name: a.Name, + Namespace: a.Namespace, + Status: "Pending", + Created: a.CreatedDate, + Started: a.Started.Format("2006-01-02 15:04:05"), + Conditions: Conditions{ + PodRunning: a.StepCount > 0 && a.StepCount < a.StepMax, + Completed: a.StepCount == a.StepMax, + }, + Progress: fmt.Sprintf("%v/%v", a.StepCount, a.StepMax), + Duration: "0s", + Logs: []string{}, + } + +} + +func (a *ArgoLogs) StartStepRecording(current_watch *ArgoWatch, logger zerolog.Logger) { + jsonified, _ := json.Marshal(current_watch) + logger.Info().Msg(string(jsonified)) a.StepCount += 1 a.Started = time.Now() } -func (a *ArgoLogs) StopStepRecording(inputs []string) *ArgoWatch { +func (a *ArgoLogs) StopStepRecording(current *ArgoWatch) *ArgoWatch { fn := strings.Split(a.Name, "_") logs := []string{} err := false end := "" - for _, input := range inputs { + for _, input := range current.Logs { line := strings.TrimSpace(input) if line == "" || !strings.Contains(line, fn[0]) || !strings.Contains(line, ":") { continue @@ -107,22 +133,13 @@ func (a *ArgoLogs) StopStepRecording(inputs []string) *ArgoWatch { timeE, _ := time.Parse("2006-01-02T15:04:05", end) duration = timeE.Sub(a.Started).Seconds() } - argo := &ArgoWatch{ - Name: a.Name, - Namespace: a.Namespace, - Status: status, - Created: a.CreatedDate, - Started: a.Started.Format("2006-01-02 15:04:05"), - Conditions: Conditions{ - PodRunning: a.StepCount > 0 && a.StepCount < a.StepMax, - Completed: a.StepCount == a.StepMax, - }, - Progress: fmt.Sprintf("%v/%v", a.StepCount, a.StepMax), - Duration: fmt.Sprintf("%v", fmt.Sprintf("%.2f", duration)+"s"), - Logs: logs, + current.Conditions = Conditions{ + PodRunning: a.StepCount > 0 && a.StepCount < a.StepMax, + Completed: a.StepCount == a.StepMax, } - if !argo.Completed { - a.StartStepRecording() - } - return argo + current.Progress = fmt.Sprintf("%v/%v", a.StepCount, a.StepMax) + current.Duration = fmt.Sprintf("%v", fmt.Sprintf("%.2f", duration)+"s") + + current.Status = status + return current } diff --git a/models/template.go b/models/template.go index c2e22ab..e9f36df 100644 --- a/models/template.go +++ b/models/template.go @@ -3,8 +3,8 @@ package models import ( "strings" - "cloud.o-forge.io/core/oc-lib/models/resources/processing" - "cloud.o-forge.io/core/oc-lib/models/resources/storage" + "cloud.o-forge.io/core/oc-lib/models/common/models" + "cloud.o-forge.io/core/oc-lib/models/resources" ) type Parameter struct { @@ -38,9 +38,9 @@ func (c *Container) AddVolumeMount(volumeMount VolumeMount, volumes []VolumeMoun } type VolumeMount struct { - Name string `yaml:"name"` - MountPath string `yaml:"mountPath"` - Storage *storage.StorageResource `yaml:"-"` + Name string `yaml:"name"` + MountPath string `yaml:"mountPath"` + Storage *resources.StorageResource `yaml:"-"` } type Task struct { @@ -60,51 +60,80 @@ type TemplateMetadata struct { Labels map[string]string `yaml:"labels,omitempty"` } +type Secret struct { + Name string `yaml:"name"` + Key string `yaml:"key"` +} + +type Key struct { + Key string `yaml:"key"` + Bucket string `yaml:"bucket"` + EndPoint string `yaml:"endpoint"` + Insecure bool `yaml:"insecure"` + AccessKeySecret *Secret `yaml accessKeySecret` + SecretKeySecret *Secret `yaml secretKeySecret` +} + +type Artifact struct { + Name string `yaml:"name"` + Path string `yaml:"path"` + S3 *Key `yaml:"s3,omitempty"` +} + +type InOut struct { + Parameters []Parameter `yaml:"parameters"` + Artifacts []Artifact `yaml:"artifacts,omitempty"` +} + type Template struct { - Name string `yaml:"name"` - Inputs struct { - Parameters []Parameter `yaml:"parameters"` - } `yaml:"inputs,omitempty"` + Name string `yaml:"name"` + Inputs InOut `yaml:"inputs,omitempty"` + Outputs InOut `yaml:"outputs,omitempty"` Container Container `yaml:"container,omitempty"` Dag *Dag `yaml:"dag,omitempty"` Metadata TemplateMetadata `yaml:"metadata,omitempty"` Resource ServiceResource `yaml:"resource,omitempty"` } -func (template *Template) CreateContainer(processing *processing.ProcessingResource, dag *Dag) { - container := Container{Image: processing.Container.Image} +func (template *Template) CreateContainer(processing *resources.ProcessingResource, dag *Dag, templateName string) { + instance := processing.GetSelectedInstance() + if instance == nil { + return + } + inst := instance.(*resources.ProcessingInstance) + container := Container{Image: inst.Access.Container.Image} if container.Image == "" { return } container.Command = []string{"sh", "-c"} // all is bash - for name := range processing.Container.Env { - template.Inputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: name}) + for _, v := range inst.Env { + template.Inputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name}) } - for _, a := range strings.Split(processing.Container.Args, " ") { - container.Args = append(container.Args, template.replacePerEnv(a, processing.Container.Env, dag)) + for _, v := range inst.Inputs { + template.Inputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name}) } - cmd := strings.ReplaceAll(processing.Container.Command, container.Image, "") - container.Args = []string{cmd + " " + strings.Join(container.Args, " ")} + for _, v := range inst.Inputs { + template.Outputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name}) + } + cmd := strings.ReplaceAll(inst.Access.Container.Command, container.Image, "") + container.Args = append(container.Args, "echo "+templateName+" && ") // a casual echo to know where we are for logs purpose + for _, a := range strings.Split(cmd, " ") { + container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env)) + } + for _, a := range strings.Split(inst.Access.Container.Args, " ") { + container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env)) + } + container.Args = []string{strings.Join(container.Args, " ")} template.Container = container } -func (template *Template) replacePerEnv(arg string, envs map[string]string, dag *Dag) string { - for k, v := range envs { - if strings.Contains(arg, k) { - value := v - for _, task := range dag.Tasks { - if task.Name == template.Name { - for _, p := range task.Arguments.Parameters { - if p.Name == k { - value = p.Value - break - } - } - } - } - arg = strings.ReplaceAll(arg, "$"+k, value) - arg = strings.ReplaceAll(arg, "${"+k+"}", value) - arg = strings.ReplaceAll(arg, k, value) +func (template *Template) ReplacePerEnv(arg string, envs []models.Param) string { + for _, v := range envs { + if strings.Contains(arg, v.Name) { + value := "{{ inputs.parameters." + v.Name + " }}" + arg = strings.ReplaceAll(arg, v.Name, value) + arg = strings.ReplaceAll(arg, "$"+v.Name, value) + arg = strings.ReplaceAll(arg, "$", "") } } return arg diff --git a/tools/interface.go b/tools/interface.go new file mode 100644 index 0000000..2b356d8 --- /dev/null +++ b/tools/interface.go @@ -0,0 +1,29 @@ +package tools + +import ( + "errors" + "io" + "oc-monitord/models" + "sync" +) + +type Tool interface { + CreateArgoWorkflow(path string, ns string) (string, error) + CreateAccessSecret(ns string, login string, password string) (string, error) + LogWorkflow(execID string, namespace string, workflowName string, argoFilePath string, stepMax int, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, + argoLogs *models.ArgoLogs, seen []string, + logFunc func(argoFilePath string, stepMax int, pipe io.ReadCloser, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, + argoLogs *models.ArgoLogs, seen []string, wg *sync.WaitGroup)) error +} + +var _service = map[string]func() (Tool, error){ + "kubernetes": NewKubernetesTool, +} + +func NewService(name string) (Tool, error) { + service, ok := _service[name] + if !ok { + return nil, errors.New("service not found") + } + return service() +} diff --git a/tools/kubernetes.go b/tools/kubernetes.go new file mode 100644 index 0000000..c5142c8 --- /dev/null +++ b/tools/kubernetes.go @@ -0,0 +1,181 @@ +package tools + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "io" + "oc-monitord/conf" + "oc-monitord/models" + "oc-monitord/utils" + "os" + "sync" + "time" + + "cloud.o-forge.io/core/oc-lib/models/common/enum" + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned" + "github.com/google/uuid" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +type KubernetesTools struct { + Set *kubernetes.Clientset + VersionedSet *versioned.Clientset +} + +func NewKubernetesTool() (Tool, error) { + // Load Kubernetes config (from ~/.kube/config) + config := &rest.Config{ + Host: conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort, + TLSClientConfig: rest.TLSClientConfig{ + CAData: []byte(conf.GetConfig().KubeCA), + CertData: []byte(conf.GetConfig().KubeCert), + KeyData: []byte(conf.GetConfig().KubeData), + }, + } + + // Create clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, errors.New("Error creating Kubernetes client: " + err.Error()) + } + + clientset2, err := versioned.NewForConfig(config) + if err != nil { + return nil, errors.New("Error creating Kubernetes versionned client: " + err.Error()) + } + return &KubernetesTools{ + Set: clientset, + VersionedSet: clientset2, + }, nil +} + +func (k *KubernetesTools) LogWorkflow(execID string, namespace string, workflowName string, argoFilePath string, stepMax int, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, argoLogs *models.ArgoLogs, + seen []string, logFunc func(argoFilePath string, stepMax int, pipe io.ReadCloser, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, argoLogs *models.ArgoLogs, seen []string, wg *sync.WaitGroup)) error { + exec := utils.GetExecution(execID) + if exec == nil { + return errors.New("Could not retrieve workflow ID from execution ID " + execID) + } + if exec.State != enum.SCHEDULED { + return nil + } + k.logWorkflow(namespace, workflowName, argoFilePath, stepMax, current_watch, previous_watch, argoLogs, seen, logFunc) + return k.LogWorkflow(execID, namespace, workflowName, argoFilePath, stepMax, current_watch, previous_watch, argoLogs, seen, logFunc) +} + +func (k *KubernetesTools) logWorkflow(namespace string, workflowName string, argoFilePath string, stepMax int, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, argoLogs *models.ArgoLogs, + seen []string, + logFunc func(argoFilePath string, stepMax int, pipe io.ReadCloser, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, argoLogs *models.ArgoLogs, seen []string, wg *sync.WaitGroup)) error { + // List pods related to the Argo workflow + labelSelector := fmt.Sprintf("workflows.argoproj.io/workflow=%s", workflowName) + for retries := 0; retries < 10; retries++ { // Retry for up to ~20 seconds + // List workflow pods + wfPods, err := k.Set.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + if err != nil { + return err + } + // If we found pods, stream logs + if len(wfPods.Items) > 0 { + var wg sync.WaitGroup + // Stream logs from all matching pods + for _, pod := range wfPods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go k.streamLogs(namespace, pod.Name, container.Name, argoFilePath, stepMax, &wg, current_watch, previous_watch, argoLogs, seen, logFunc) + } + } + wg.Wait() + return nil + } + time.Sleep(2 * time.Second) // Wait before retrying + } + return errors.New("no pods found for the workflow") +} + +// Function to stream logs +func (k *KubernetesTools) streamLogs(namespace string, podName string, containerName string, + argoFilePath string, stepMax int, wg *sync.WaitGroup, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, argoLogs *models.ArgoLogs, seen []string, + logFunc func(argo_file_path string, stepMax int, pipe io.ReadCloser, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch, argoLogs *models.ArgoLogs, seen []string, wg *sync.WaitGroup)) { + req := k.Set.CoreV1().Pods(namespace).GetLogs(podName, &corev1.PodLogOptions{ + Container: containerName, // Main container + Follow: true, // Equivalent to -f flag in kubectl logs + }) + defer wg.Done() + // Open stream + stream, err := req.Stream(context.Background()) + if err != nil { + return + } + defer stream.Close() + var internalWg sync.WaitGroup + logFunc(argoFilePath, stepMax, stream, current_watch, previous_watch, argoLogs, seen, &internalWg) + internalWg.Wait() +} + +func (k *KubernetesTools) CreateArgoWorkflow(path string, ns string) (string, error) { + // Read workflow YAML file + workflowYAML, err := os.ReadFile(path) + if err != nil { + return "", err + } + // Decode the YAML into a Workflow struct + scheme := runtime.NewScheme() + _ = wfv1.AddToScheme(scheme) + codecs := serializer.NewCodecFactory(scheme) + decode := codecs.UniversalDeserializer().Decode + + obj, _, err := decode(workflowYAML, nil, nil) + if err != nil { + return "", errors.New("failed to decode YAML: " + err.Error()) + } + + workflow, ok := obj.(*wfv1.Workflow) + if !ok { + return "", errors.New("decoded object is not a Workflow") + } + + // Create the workflow in the "argo" namespace + createdWf, err := k.VersionedSet.ArgoprojV1alpha1().Workflows(ns).Create(context.Background(), workflow, metav1.CreateOptions{}) + if err != nil { + return "", errors.New("failed to create workflow: " + err.Error()) + } + fmt.Printf("workflow %s created in namespace %s\n", createdWf.Name, "argo") + return createdWf.Name, nil +} + +func (k *KubernetesTools) CreateAccessSecret(ns string, login string, password string) (string, error) { + // Namespace where the secret will be created + namespace := "default" + // Encode the secret data (Kubernetes requires base64-encoded values) + secretData := map[string][]byte{ + "access-key": []byte(base64.StdEncoding.EncodeToString([]byte(login))), + "secret-key": []byte(base64.StdEncoding.EncodeToString([]byte(password))), + } + + // Define the Secret object + name := uuid.New().String() + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Type: v1.SecretTypeOpaque, + Data: secretData, + } + // Create the Secret in Kubernetes + _, err := k.Set.CoreV1().Secrets(namespace).Create(context.Background(), secret, metav1.CreateOptions{}) + if err != nil { + return "", errors.New("Error creating secret: " + err.Error()) + } + return name, nil +} diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..1222230 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,18 @@ +package utils + +import ( + "oc-monitord/conf" + + oclib "cloud.o-forge.io/core/oc-lib" + "cloud.o-forge.io/core/oc-lib/models/workflow_execution" +) + +func GetExecution(exec_id string) *workflow_execution.WorkflowExecution { + res := oclib.NewRequest(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), "", conf.GetConfig().PeerID, []string{}, nil).LoadOne(exec_id) + if res.Code != 200 { + logger := oclib.GetLogger() + logger.Error().Msg("Could not retrieve workflow ID from execution ID " + exec_id) + return nil + } + return res.ToWorkflowExecution() +} diff --git a/workflow_builder/argo_builder.go b/workflow_builder/argo_builder.go index a49a51f..2b146eb 100644 --- a/workflow_builder/argo_builder.go +++ b/workflow_builder/argo_builder.go @@ -6,15 +6,16 @@ package workflow_builder import ( "fmt" + "oc-monitord/conf" . "oc-monitord/models" + tools2 "oc-monitord/tools" "os" - "regexp" "strings" "time" oclib "cloud.o-forge.io/core/oc-lib" - "cloud.o-forge.io/core/oc-lib/models/resources/processing" - "cloud.o-forge.io/core/oc-lib/models/resources/workflow/graph" + "cloud.o-forge.io/core/oc-lib/models/common/enum" + "cloud.o-forge.io/core/oc-lib/models/resources" w "cloud.o-forge.io/core/oc-lib/models/workflow" "github.com/nwtgck/go-fakelish" "github.com/rs/zerolog" @@ -39,14 +40,6 @@ type Workflow struct { Spec Spec `yaml:"spec,omitempty"` } -func (b *Workflow) setDag(dag *Dag) { - for _, t := range b.Spec.Templates { - if t.Name == "dag" { - t.Dag = dag - } - } -} - func (b *Workflow) getDag() *Dag { for _, t := range b.Spec.Templates { if t.Name == "dag" { @@ -65,10 +58,12 @@ type Spec struct { Timeout int `yaml:"activeDeadlineSeconds,omitempty"` } -func (b *ArgoBuilder) CreateDAG(write bool) (string, int, []string, []string, error) { - +// TODO: found on a processing instance linked to storage +// add s3, gcs, azure, etc if needed on a link between processing and storage +func (b *ArgoBuilder) CreateDAG(namespace string, write bool) (string, int, []string, []string, error) { + fmt.Println("Creating DAG", b.OriginWorkflow.Graph.Items) // handle services by checking if there is only one processing with hostname and port - firstItems, lastItems, volumes := b.createTemplates() + firstItems, lastItems, volumes := b.createTemplates(namespace) b.createVolumes(volumes) if b.Timeout > 0 { @@ -97,41 +92,44 @@ func (b *ArgoBuilder) CreateDAG(write bool) (string, int, []string, []string, er logger.Error().Msg("Could not write the yaml file") return "", 0, firstItems, lastItems, err } - return file_name, len(b.Workflow.getDag().Tasks), firstItems, lastItems, nil + return workflows_dir + file_name, len(b.Workflow.getDag().Tasks), firstItems, lastItems, nil } -func (b *ArgoBuilder) createTemplates() ([]string, []string, []VolumeMount) { +func (b *ArgoBuilder) createTemplates(namespace string) ([]string, []string, []VolumeMount) { volumes := []VolumeMount{} firstItems := []string{} lastItems := []string{} - for _, comp := range b.OriginWorkflow.GetProcessings() { - if comp.Processing.Container != nil { - volumes, firstItems, lastItems = b.createArgoTemplates( - comp.ID, comp.Processing, volumes, firstItems, lastItems) - } else { - logger.Error().Msg("Not enough configuration setup, template can't be created : " + comp.Processing.GetName()) + items := b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing) + fmt.Println("Creating templates", len(items)) + for _, item := range b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing) { + instance := item.Processing.GetSelectedInstance() + fmt.Println("Creating template for", item.Processing.GetName(), instance) + if instance == nil || instance.(*resources.ProcessingInstance).Access == nil && instance.(*resources.ProcessingInstance).Access.Container != nil { + logger.Error().Msg("Not enough configuration setup, template can't be created : " + item.Processing.GetName()) return firstItems, lastItems, volumes } + volumes, firstItems, lastItems = b.createArgoTemplates(namespace, + item.ID, item.Processing, volumes, firstItems, lastItems) } firstWfTasks := map[string][]string{} latestWfTasks := map[string][]string{} relatedWfTasks := map[string][]string{} - for _, wf := range b.OriginWorkflow.GetWorkflows() { - realWorkflow, code, err := w.New().LoadOne(wf.Workflow.WorkflowID) + for _, wf := range b.OriginWorkflow.Workflows { + realWorkflow, code, err := w.NewAccessor(nil).LoadOne(wf) if code != 200 { logger.Error().Msg("Error loading the workflow : " + err.Error()) continue } subBuilder := ArgoBuilder{OriginWorkflow: realWorkflow.(*w.Workflow), Timeout: b.Timeout} - _, _, fi, li, err := subBuilder.CreateDAG(false) + _, _, fi, li, err := subBuilder.CreateDAG(namespace, false) if err != nil { logger.Error().Msg("Error creating the subworkflow : " + err.Error()) continue } - firstWfTasks[wf.ID] = fi - if ok, depsOfIds := subBuilder.isArgoDependancy(wf.ID); ok { // IS BEFORE - latestWfTasks[wf.ID] = li - relatedWfTasks[wf.ID] = depsOfIds + firstWfTasks[wf] = fi + if ok, depsOfIds := subBuilder.isArgoDependancy(wf); ok { // IS BEFORE + latestWfTasks[wf] = li + relatedWfTasks[wf] = depsOfIds } subDag := subBuilder.Workflow.getDag() d := b.Workflow.getDag() @@ -180,26 +178,87 @@ func (b *ArgoBuilder) createTemplates() ([]string, []string, []VolumeMount) { return firstItems, lastItems, volumes } -func (b *ArgoBuilder) createArgoTemplates(id string, - processing *processing.ProcessingResource, +func (b *ArgoBuilder) createArgoTemplates(namespace string, + id string, + processing *resources.ProcessingResource, volumes []VolumeMount, firstItems []string, lastItems []string) ([]VolumeMount, []string, []string) { _, firstItems, lastItems = b.addTaskToArgo(b.Workflow.getDag(), id, processing, firstItems, lastItems) template := &Template{Name: getArgoName(processing.GetName(), id)} - template.CreateContainer(processing, b.Workflow.getDag()) + fmt.Println("Creating template for", template.Name) + template.CreateContainer(processing, b.Workflow.getDag(), template.Name) // get datacenter from the processing if processing.IsService { b.CreateService(id, processing) template.Metadata.Labels = make(map[string]string) template.Metadata.Labels["app"] = "oc-service-" + processing.GetName() // Construct the template for the k8s service and add a link in graph between k8s service and processing } - storages := b.OriginWorkflow.GetStoragesByRelatedProcessing(id) - for _, storage := range storages { - if storage.Local { + related := b.OriginWorkflow.GetByRelatedProcessing(id, b.OriginWorkflow.Graph.IsStorage) + for _, r := range related { + storage := r.Node.(*resources.StorageResource) + for _, linkToStorage := range r.Links { + for _, rw := range linkToStorage.StorageLinkInfos { + art := Artifact{Path: template.ReplacePerEnv(rw.Source, linkToStorage.Env)} + if rw.Write { + art.Name = storage.GetName() + "-" + rw.Destination + "-input-write" + } else { + art.Name = storage.GetName() + "-" + rw.Destination + "-input-read" + } + if storage.StorageType == enum.S3 { + art.S3 = &Key{ + Key: template.ReplacePerEnv(rw.Destination+"/"+rw.FileName, linkToStorage.Env), + Insecure: true, // temporary + } + sel := storage.GetSelectedInstance() + if sel != nil { + if sel.(*resources.StorageResourceInstance).Credentials != nil { + tool, err := tools2.NewService(conf.GetConfig().Mode) + if err != nil || tool == nil { + logger.Error().Msg("Could not create the access secret") + } else { + id, err := tool.CreateAccessSecret(namespace, + sel.(*resources.StorageResourceInstance).Credentials.Login, + sel.(*resources.StorageResourceInstance).Credentials.Pass) + if err == nil { + art.S3.AccessKeySecret = &Secret{ + Name: id, + Key: "access-key", + } + art.S3.SecretKeySecret = &Secret{ + Name: id, + Key: "secret-key", + } + } + } + } + art.S3.Key = strings.ReplaceAll(art.S3.Key, sel.(*resources.StorageResourceInstance).Source+"/", "") + art.S3.Key = strings.ReplaceAll(art.S3.Key, sel.(*resources.StorageResourceInstance).Source, "") + splits := strings.Split(art.S3.EndPoint, "/") + if len(splits) > 1 { + art.S3.Bucket = splits[0] + art.S3.EndPoint = strings.Join(splits[1:], "/") + } else { + art.S3.Bucket = splits[0] + } + } + } + if rw.Write { + template.Outputs.Artifacts = append(template.Inputs.Artifacts, art) + } else { + template.Inputs.Artifacts = append(template.Outputs.Artifacts, art) + } + } + } + index := 0 + if storage.SelectedInstanceIndex != nil && (*storage.SelectedInstanceIndex) >= 0 { + index = *storage.SelectedInstanceIndex + } + s := storage.Instances[index] + if s.Local { volumes = template.Container.AddVolumeMount(VolumeMount{ Name: strings.ReplaceAll(strings.ToLower(storage.GetName()), " ", "-"), - MountPath: storage.Path, + MountPath: s.Source, Storage: storage, }, volumes) } @@ -207,15 +266,28 @@ func (b *ArgoBuilder) createArgoTemplates(id string, b.Workflow.Spec.Templates = append(b.Workflow.Spec.Templates, *template) return volumes, firstItems, lastItems } -func (b *ArgoBuilder) addTaskToArgo(dag *Dag, graphItemID string, processing *processing.ProcessingResource, +func (b *ArgoBuilder) addTaskToArgo(dag *Dag, graphItemID string, processing *resources.ProcessingResource, firstItems []string, lastItems []string) (*Dag, []string, []string) { unique_name := getArgoName(processing.GetName(), graphItemID) step := Task{Name: unique_name, Template: unique_name} - if processing.Container != nil { - for name, value := range processing.Container.Env { + instance := processing.GetSelectedInstance() + if instance != nil { + for _, value := range instance.(*resources.ProcessingInstance).Env { step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{ - Name: name, - Value: b.affectVariableEnv(value, b.OriginWorkflow.Graph), + Name: value.Name, + Value: value.Value, + }) + } + for _, value := range instance.(*resources.ProcessingInstance).Inputs { + step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{ + Name: value.Name, + Value: value.Value, + }) + } + for _, value := range instance.(*resources.ProcessingInstance).Outputs { + step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{ + Name: value.Name, + Value: value.Value, }) } } @@ -237,32 +309,17 @@ func (b *ArgoBuilder) addTaskToArgo(dag *Dag, graphItemID string, processing *pr return dag, firstItems, lastItems } -func (b *ArgoBuilder) affectVariableEnv(envVar string, graph *graph.Graph) string { - var myExp = regexp.MustCompile(`(\{\{.*\}\})`) // regex to find all the variables in the command - matches := myExp.FindAllString(envVar, -1) // find all the variables in the command - for _, match := range matches { // for each variable in the command - splitted := strings.Split( // split the variable to get the inout and the vars only - strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(match, "{{", ""), "}}", ""), " ", ""), "_") - if len(splitted) < 3 { // if the variable is not well formatted, we skip it - logger.Error().Msgf("The variable %v is not well formatted", match) - continue - } - graphItemID := splitted[1] // graphitemid is the id of the object - vars := splitted[2] // vars is the name of the variable of the object - _, obj := graph.GetResource(graphItemID) - if obj != nil { - envVar = strings.ReplaceAll(envVar, match, fmt.Sprintf("%v", obj.Serialize()[vars])) - } - } - return envVar -} - func (b *ArgoBuilder) createVolumes(volumes []VolumeMount) { // TODO : one think about remote volume but TG for _, volume := range volumes { + index := 0 + if volume.Storage.SelectedInstanceIndex != nil && (*volume.Storage.SelectedInstanceIndex) >= 0 { + index = *volume.Storage.SelectedInstanceIndex + } + storage := volume.Storage.Instances[index] new_volume := VolumeClaimTemplate{} new_volume.Metadata.Name = strings.ReplaceAll(strings.ToLower(volume.Name), " ", "-") new_volume.Spec.AccessModes = []string{"ReadWriteOnce"} - new_volume.Spec.Resources.Requests.Storage = fmt.Sprintf("%v", volume.Storage.Size) + volume.Storage.SizeType.ToArgo() + new_volume.Spec.Resources.Requests.Storage = fmt.Sprintf("%v", storage.SizeGB) + storage.SizeType.ToArgo() b.Workflow.Spec.Volumes = append(b.Workflow.Spec.Volumes, new_volume) } } @@ -271,6 +328,10 @@ func (b *ArgoBuilder) isArgoDependancy(id string) (bool, []string) { dependancyOfIDs := []string{} isDeps := false for _, link := range b.OriginWorkflow.Graph.Links { + if _, ok := b.OriginWorkflow.Graph.Items[link.Destination.ID]; !ok { + fmt.Println("Could not find the source of the link", link.Destination.ID) + continue + } source := b.OriginWorkflow.Graph.Items[link.Destination.ID].Processing if id == link.Source.ID && source != nil { isDeps = true @@ -287,6 +348,10 @@ func (b *ArgoBuilder) isArgoDependancy(id string) (bool, []string) { func (b *ArgoBuilder) getArgoDependencies(id string) (dependencies []string) { for _, link := range b.OriginWorkflow.Graph.Links { + if _, ok := b.OriginWorkflow.Graph.Items[link.Source.ID]; !ok { + fmt.Println("Could not find the source of the link", link.Source.ID) + continue + } source := b.OriginWorkflow.Graph.Items[link.Source.ID].Processing if id == link.Destination.ID && source != nil { dependency_name := getArgoName(source.GetName(), link.Source.ID) diff --git a/workflow_builder/argo_services.go b/workflow_builder/argo_services.go index 3712798..f95740a 100644 --- a/workflow_builder/argo_services.go +++ b/workflow_builder/argo_services.go @@ -4,11 +4,11 @@ import ( "oc-monitord/models" "strings" - "cloud.o-forge.io/core/oc-lib/models/resources/processing" + "cloud.o-forge.io/core/oc-lib/models/resources" "gopkg.in/yaml.v3" ) -func (b *ArgoBuilder) CreateService(id string, processing *processing.ProcessingResource) { +func (b *ArgoBuilder) CreateService(id string, processing *resources.ProcessingResource) { new_service := models.Service{ APIVersion: "v1", Kind: "Service", @@ -28,16 +28,19 @@ func (b *ArgoBuilder) CreateService(id string, processing *processing.Processing b.Services = append(b.Services, &new_service) } -func (b *ArgoBuilder) completeServicePorts(service *models.Service, id string, processing *processing.ProcessingResource) { - for _, execute := range processing.Expose { - if execute.PAT != 0 { - new_port_translation := models.ServicePort{ - Name: strings.ToLower(processing.Name) + id, - Port: execute.Port, - TargetPort: execute.PAT, - Protocol: "TCP", +func (b *ArgoBuilder) completeServicePorts(service *models.Service, id string, processing *resources.ProcessingResource) { + instance := processing.GetSelectedInstance() + if instance != nil && instance.(*resources.ProcessingInstance).Access != nil && instance.(*resources.ProcessingInstance).Access.Container != nil { + for _, execute := range instance.(*resources.ProcessingInstance).Access.Container.Exposes { + if execute.PAT != 0 { + new_port_translation := models.ServicePort{ + Name: strings.ToLower(processing.Name) + id, + Port: execute.Port, + TargetPort: execute.PAT, + Protocol: "TCP", + } + service.Spec.Ports = append(service.Spec.Ports, new_port_translation) } - service.Spec.Ports = append(service.Spec.Ports, new_port_translation) } } } @@ -46,7 +49,6 @@ func (b *ArgoBuilder) addServiceToArgo() error { for _, service := range b.Services { service_manifest, err := yaml.Marshal(service) if err != nil { - logger.Error().Msg("Could not marshal service manifest : " + err.Error()) return err } service_template := models.Template{Name: "workflow-service-pod", diff --git a/workflow_builder/graph.go b/workflow_builder/graph.go index 6e1fd6c..0f5168c 100644 --- a/workflow_builder/graph.go +++ b/workflow_builder/graph.go @@ -13,20 +13,21 @@ type WorflowDB struct { } // Create the obj!ects from the mxgraphxml stored in the workflow given as a parameter -func (w *WorflowDB) LoadFrom(workflow_id string) error { +func (w *WorflowDB) LoadFrom(workflow_id string, peerID string) error { + fmt.Println("Loading workflow from " + workflow_id) var err error - if w.Workflow, err = w.getWorkflow(workflow_id); err != nil { + if w.Workflow, err = w.getWorkflow(workflow_id, peerID); err != nil { return err } return nil } // Use oclib to retrieve the graph contained in the workflow referenced -func (w *WorflowDB) getWorkflow(workflow_id string) (workflow *workflow.Workflow, err error) { +func (w *WorflowDB) getWorkflow(workflow_id string, peerID string) (workflow *workflow.Workflow, err error) { logger := oclib.GetLogger() - lib_data := oclib.LoadOne(oclib.LibDataEnum(oclib.WORKFLOW), workflow_id) - fmt.Println(lib_data.Code, lib_data.Err) + lib_data := oclib.NewRequest(oclib.LibDataEnum(oclib.WORKFLOW), "", peerID, []string{}, nil).LoadOne(workflow_id) + fmt.Println("ERR", lib_data.Code, lib_data.Err) if lib_data.Code != 200 { logger.Error().Msg("Error loading the graph") return workflow, errors.New(lib_data.Err) @@ -40,15 +41,15 @@ func (w *WorflowDB) getWorkflow(workflow_id string) (workflow *workflow.Workflow return new_wf, nil } -func (w *WorflowDB) ExportToArgo(timeout int) (string, int, error) { +func (w *WorflowDB) ExportToArgo(namespace string, timeout int) (string, int, error) { logger := oclib.GetLogger() - + fmt.Println("Exporting to Argo", w.Workflow) if len(w.Workflow.Name) == 0 || w.Workflow.Graph == nil { return "", 0, fmt.Errorf("can't export a graph that has not been loaded yet") } argo_builder := ArgoBuilder{OriginWorkflow: w.Workflow, Timeout: timeout} - filename, stepMax, _, _, err := argo_builder.CreateDAG(true) + filename, stepMax, _, _, err := argo_builder.CreateDAG(namespace, true) if err != nil { logger.Error().Msg("Could not create the argo file for " + w.Workflow.Name) return "", 0, err diff --git a/workflow_builder/graph_tests.go b/workflow_builder/graph_tests.go index fea3a23..a77f501 100644 --- a/workflow_builder/graph_tests.go +++ b/workflow_builder/graph_tests.go @@ -4,7 +4,7 @@ import ( "testing" ) -func TestGetGraph(t *testing.T){ +func TestGetGraph(t *testing.T) { w := WorflowDB{} - w.LoadFrom("test-log") + w.LoadFrom("test-log", "") }