Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e2399c6853 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,4 +22,3 @@
|
|||||||
go.work
|
go.work
|
||||||
|
|
||||||
argo_workflows/*
|
argo_workflows/*
|
||||||
env.env
|
|
||||||
@@ -23,6 +23,4 @@ FROM scratch
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=builder /app/oc-monitord .
|
COPY --from=builder /app/oc-monitord .
|
||||||
|
|
||||||
ENTRYPOINT ["./oc-monitord"]
|
|
||||||
18
Makefile
18
Makefile
@@ -3,8 +3,6 @@
|
|||||||
build: clean
|
build: clean
|
||||||
go build .
|
go build .
|
||||||
|
|
||||||
dev: build
|
|
||||||
|
|
||||||
run:
|
run:
|
||||||
./oc-monitord
|
./oc-monitord
|
||||||
|
|
||||||
@@ -12,16 +10,16 @@ clean:
|
|||||||
rm -rf oc-monitord
|
rm -rf oc-monitord
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
DOCKER_BUILDKIT=1 docker build -t oc-monitord -f Dockerfile .
|
DOCKER_BUILDKIT=1 docker build -t oc/oc-monitord:0.0.1 -f Dockerfile .
|
||||||
docker tag oc-monitord opencloudregistry/oc-monitord:latest
|
docker tag oc/oc-monitord:0.0.1 oc/oc-monitord:latest
|
||||||
|
docker tag oc/oc-monitord:0.0.1 oc-monitord:latest
|
||||||
|
|
||||||
publish-kind:
|
publish-kind:
|
||||||
kind load docker-image opencloudregistry/oc-monitord:latest --name $(CLUSTER_NAME)
|
kind load docker-image oc/oc-monitord:0.0.1 --name opencloud
|
||||||
|
|
||||||
publish-registry:
|
publish-registry:
|
||||||
docker push opencloudregistry/oc-monitord:latest
|
@echo "TODO"
|
||||||
|
|
||||||
all: docker publish-kind
|
all: docker publish-kind publish-registry
|
||||||
|
|
||||||
ci: docker publish-registry
|
.PHONY: build run clean docker publish-kind publish-registry
|
||||||
|
|
||||||
.PHONY: build run clean docker publish-kind publish-registry
|
|
||||||
75
README.md
75
README.md
@@ -1,47 +1,64 @@
|
|||||||
# oc-monitor
|
# oc-monitor
|
||||||
|
|
||||||
DO :
|
## Deploy in k8s (dev)
|
||||||
make build
|
|
||||||
|
|
||||||
## Summary
|
While a registry with all of the OC docker images has not been set-up we can export this image to k3s ctr
|
||||||
|
|
||||||
oc-monitord is a daemon which can be run :
|
> docker save oc-monitord:latest | sudo k3s ctr images import -
|
||||||
- as a binary
|
|
||||||
- as a container
|
|
||||||
|
|
||||||
It is used to perform several actions regarding the execution of an Open Cloud workflow :
|
Then in the pod manifest for oc-monitord use :
|
||||||
- generating a YAML file that can be interpreted by **Argo Workflow** to create and execute pods in a kubernetes environment
|
|
||||||
- setting up the different resources needed to execute a workflow over several peers/kubernetes nodes with **Admiralty** : token, secrets, targets and sources
|
|
||||||
- creating the workflow and logging the output from
|
|
||||||
- Argo watch, which gives informations about the workflow in general (phase, number of steps executed, status...)
|
|
||||||
- Pods : which are the logs generated by the pods
|
|
||||||
|
|
||||||
To execute, the daemon needs several options :
|
```
|
||||||
- **-u** :
|
image: docker.io/library/oc-monitord
|
||||||
- **-m** :
|
imagePullPolicy: Never
|
||||||
- **-d** :
|
```
|
||||||
- **-e** :
|
|
||||||
|
|
||||||
# Notes features/admiralty-docker
|
Not doing so will end up in the pod having a `ErrorImagePull`
|
||||||
|
|
||||||
- When executing monitord as a container we need to change any url with "localhost" to the container's host IP.
|
## Allow argo to create services
|
||||||
|
|
||||||
We can :
|
In order for monitord to expose **open cloud services** on the node, we need to give him permission to create **k8s services**.
|
||||||
- declare a new parameter 'HOST_IP'
|
|
||||||
- decide that no peer can have "http://localhost" as its url and use an attribute from the peer object or isMyself() from oc-lib if a peer is the current host.
|
For that we can update the RBAC configuration for a role already created by argo :
|
||||||
|
|
||||||
|
### Manually edit the rbac authorization
|
||||||
|
|
||||||
|
> kubectl edit roles.rbac.authorization.k8s.io -n argo argo-role
|
||||||
|
|
||||||
|
In rules add a new entry :
|
||||||
|
|
||||||
|
```
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
```
|
||||||
|
|
||||||
|
### Patch the rbac authorization with a one liner
|
||||||
|
|
||||||
|
> kubectl patch role argo-role -n argo --type='json' -p='[{"op": "add", "path": "/rules/-", "value": {"apiGroups": [""], "resources": ["services"], "verbs": ["get","create"]}}]'
|
||||||
|
|
||||||
|
### Check wether the modification is effective
|
||||||
|
|
||||||
|
> kubectl auth can-i create services --as=system:serviceaccount:argo:argo -n argo
|
||||||
|
|
||||||
|
This command **must return "yes"**
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [ ] Allow the front to known on which IP the service are reachable
|
- [ ] Logs the output of each pods :
|
||||||
|
- logsPods() function already exists
|
||||||
|
- need to implement the logic to create each pod's logger and start the monitoring routing
|
||||||
|
- [ ] Allow the front to known on which IP the service are reachable
|
||||||
- currently doing it by using `kubectl get nodes -o wide`
|
- currently doing it by using `kubectl get nodes -o wide`
|
||||||
|
|
||||||
- [ ] Implement writing and reading from S3 bucket/MinIO when a data resource is linked to a compute resource.
|
|
||||||
|
|
||||||
|
### Adding ingress handling to support reverse proxing
|
||||||
### Adding ingress handling to support reverse proxing
|
|
||||||
|
|
||||||
- Test wether ingress-nginx is running or not
|
- Test wether ingress-nginx is running or not
|
||||||
- Do something if not found : stop running and send error log OR start installation
|
- Do something if not found : stop running and send error log OR start installation
|
||||||
-
|
-
|
||||||
|
|
||||||
@@ -18,7 +18,6 @@ type Config struct {
|
|||||||
KubeCA string
|
KubeCA string
|
||||||
KubeCert string
|
KubeCert string
|
||||||
KubeData string
|
KubeData string
|
||||||
ArgoHost string // when executed in a container will replace addresses with "localhost" in their url
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance *Config
|
var instance *Config
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 71 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB |
8
env.env
8
env.env
@@ -1,4 +1,4 @@
|
|||||||
KUBERNETES_SERVICE_HOST=192.168.1.169
|
KUBERNETES_SERVICE_HOST=kubernetes.default.svc.cluster.local
|
||||||
KUBE_CA="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTVlk3ZHZhNEdYTVdkMy9jMlhLN3JLYjlnWXgyNSthaEE0NmkyNVBkSFAKRktQL2UxSVMyWVF0dzNYZW1TTUQxaStZdzJSaVppNUQrSVZUamNtNHdhcnFvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWtlUVJpNFJiODduME5yRnZaWjZHClc2SU55NnN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnRXA5ck04WmdNclRZSHYxZjNzOW5DZXZZeWVVa3lZUk4KWjUzazdoaytJS1FDSVFDbk05TnVGKzlTakIzNDFacGZ5ays2NEpWdkpSM3BhcmVaejdMd2lhNm9kdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
KUBE_CA="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkakNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTnpNeE1qY3dPVFl3SGhjTk1qWXdNekV3TURjeE9ERTJXaGNOTXpZd016QTNNRGN4T0RFMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTnpNeE1qY3dPVFl3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReG81cXQ0MGxEekczRHJKTE1wRVBrd0ZBY1FmbC8vVE1iWjZzemMreHAKbmVzVzRTSTdXK1lWdFpRYklmV2xBMTRaazQvRFlDMHc1YlgxZU94RVVuL0pvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXBLM2pGK25IRlZSbDcwb3ZRVGZnCmZabGNQZE13Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVnkyaUx0Y0xaYm1vTnVoVHdKbU5sWlo3RVlBYjJKNW0KSjJYbG1UbVF5a2tDSUhLbzczaDBkdEtUZTlSa0NXYTJNdStkS1FzOXRFU0tBV0x1emlnYXBHYysKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
|
||||||
KUBE_CERT="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJWUxWNkFPQkdrU1F3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekl6TVRFeU1ETTJNQjRYRFRJME1EZ3dPREV3TVRNMU5sb1hEVEkxTURndwpPREV3TVRNMU5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJGQ2Q1MFdPeWdlQ2syQzcKV2FrOWY4MVAvSkJieVRIajRWOXBsTEo0ck5HeHFtSjJOb2xROFYxdUx5RjBtOTQ2Nkc0RmRDQ2dqaXFVSk92Swp3NVRPNnd5alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCVFJkOFI5cXVWK2pjeUVmL0ovT1hQSzMyS09XekFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQTArbThqTDBJVldvUTZ0dnB4cFo4NVlMalF1SmpwdXM0aDdnSXRxS3NmUVVDSUI2M2ZNdzFBMm5OVWU1TgpIUGZOcEQwSEtwcVN0Wnk4djIyVzliYlJUNklZCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRc3hXWk9pbnIrcVp4TmFEQjVGMGsvTDF5cE01VHAxOFRaeU92ektJazQKRTFsZWVqUm9STW0zNmhPeVljbnN3d3JoNnhSUnBpMW5RdGhyMzg0S0Z6MlBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBYZkVmYXJsZm8zTWhIL3lmemx6Cnl0OWlqbHN3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUxJL2dNYnNMT3MvUUpJa3U2WHVpRVMwTEE2cEJHMXgKcnBlTnpGdlZOekZsQWlFQW1wdjBubjZqN3M0MVI0QzFNMEpSL0djNE53MHdldlFmZWdEVGF1R2p3cFk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
KUBE_CERT="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrakNDQVRlZ0F3SUJBZ0lJQUkvSUg2R2Rodm93Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOemN6TVRJM01EazJNQjRYRFRJMk1ETXhNREEzTVRneE5sb1hEVEkzTURNeApNREEzTVRneE5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJQTTdBVEZQSmFMMjUrdzAKUU1vZUIxV2hBRW4vWnViM0tSRERrYnowOFhwQWJ2akVpdmdnTkdpdG4wVmVsaEZHamRmNHpBT29Nd1J3M21kbgpYSGtHVDB5alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCUVZLOThaMEMxcFFyVFJSMGVLZHhIa2o0ejFJREFLQmdncWhrak9QUVFEQWdOSkFEQkcKQWlFQXZYWll6Zk9iSUtlWTRtclNsRmt4ZS80a0E4K01ieDc1UDFKRmNlRS8xdGNDSVFDNnM0ZXlZclhQYmNWSgpxZm5EamkrZ1RacGttN0tWSTZTYTlZN2FSRGFabUE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCZURDQ0FSMmdBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwClpXNTBMV05oUURFM056TXhNamN3T1RZd0hoY05Nall3TXpFd01EY3hPREUyV2hjTk16WXdNekEzTURjeE9ERTIKV2pBak1TRXdId1lEVlFRRERCaHJNM010WTJ4cFpXNTBMV05oUURFM056TXhNamN3T1RZd1dUQVRCZ2NxaGtqTwpQUUlCQmdncWhrak9QUU1CQndOQ0FBUzV1NGVJbStvVnV1SFI0aTZIOU1kVzlyUHdJbFVPNFhIMEJWaDRUTGNlCkNkMnRBbFVXUW5FakxMdlpDWlVaYTlzTlhKOUVtWWt5S0dtQWR2TE9FbUVrbzBJd1FEQU9CZ05WSFE4QkFmOEUKQkFNQ0FxUXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QWRCZ05WSFE0RUZnUVVGU3ZmR2RBdGFVSzAwVWRIaW5jUgo1SStNOVNBd0NnWUlLb1pJemowRUF3SURTUUF3UmdJaEFMY2xtQnR4TnpSVlBvV2hoVEVKSkM1Z3VNSGsvcFZpCjFvYXJ2UVJxTWRKcUFpRUEyR1dNTzlhZFFYTEQwbFZKdHZMVkc1M3I0M0lxMHpEUUQwbTExMVZyL1MwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
|
||||||
KUBE_DATA="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5ZS1BFb1dhd1NKUzJlRW5oWmlYMk5VZlY1ZlhKV2krSVNnV09TNFE5VTlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVUozblJZN0tCNEtUWUx0WnFUMS96VS84a0Z2Sk1lUGhYMm1Vc25pczBiR3FZblkyaVZEeApYVzR2SVhTYjNqcm9iZ1YwSUtDT0twUWs2OHJEbE03ckRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
|
KUBE_DATA="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVkSTRZN3lRU1ZwRGNrblhsQmJEaXBWZHRMWEVsYVBkN3VBZHdBWFFya2xvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFOHpzQk1VOGxvdmJuN0RSQXloNEhWYUVBU2Y5bTV2Y3BFTU9SdlBUeGVrQnUrTVNLK0NBMAphSzJmUlY2V0VVYU4xL2pNQTZnekJIRGVaMmRjZVFaUFRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
|
||||||
|
|||||||
95
go.mod
95
go.mod
@@ -1,104 +1,101 @@
|
|||||||
module oc-monitord
|
module oc-monitord
|
||||||
|
|
||||||
go 1.25.0
|
go 1.23.1
|
||||||
|
|
||||||
|
toolchain go1.23.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312104524-e28b79ac0d62
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219142942-5111c9c8bec7
|
||||||
github.com/akamensky/argparse v1.4.0
|
github.com/akamensky/argparse v1.4.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/goraz/onion v0.1.3
|
github.com/goraz/onion v0.1.3
|
||||||
github.com/nwtgck/go-fakelish v0.1.3
|
github.com/nwtgck/go-fakelish v0.1.3
|
||||||
github.com/rs/zerolog v1.34.0
|
github.com/rs/zerolog v1.33.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beego/beego/v2 v2.3.8 // indirect
|
github.com/beego/beego/v2 v2.3.1 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||||
github.com/libp2p/go-libp2p/core v0.43.0-rc2 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/ugorji/go/codec v1.1.7 // indirect
|
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // 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/api v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc 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
|
google.golang.org/grpc v1.63.0 // indirect
|
||||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
|
||||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||||
github.com/argoproj/argo-workflows/v3 v3.6.4
|
github.com/argoproj/argo-workflows/v3 v3.6.4
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/biter777/countries v1.7.5 // indirect
|
github.com/biter777/countries v1.7.5 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||||
github.com/go-openapi/swag v0.23.0 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/snappy v1.0.0 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/gnostic-models v0.7.0 // indirect
|
github.com/google/gnostic-models v0.6.8 // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.17.10 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/nats-io/nats.go v1.44.0 // indirect
|
github.com/nats-io/nats.go v1.37.0 // indirect
|
||||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.23.0 // indirect
|
github.com/prometheus/client_golang v1.19.0 // indirect
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.0 // indirect
|
||||||
github.com/prometheus/common v0.65.0 // indirect
|
github.com/prometheus/common v0.48.0 // indirect
|
||||||
github.com/prometheus/procfs v0.17.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/robfig/cron v1.2.0 // indirect
|
github.com/robfig/cron v1.2.0 // indirect
|
||||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect
|
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
||||||
github.com/smartystreets/goconvey v1.6.4 // 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/x448/float16 v0.8.4 // indirect
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.17.4 // indirect
|
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||||
golang.org/x/crypto v0.44.0 // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/oauth2 v0.30.0 // indirect
|
golang.org/x/oauth2 v0.23.0 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/term v0.37.0 // indirect
|
golang.org/x/term v0.27.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
golang.org/x/time v0.9.0 // indirect
|
golang.org/x/time v0.7.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.8 // indirect
|
google.golang.org/protobuf v1.35.1 // indirect
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
k8s.io/api v0.35.1
|
k8s.io/api v0.32.1
|
||||||
k8s.io/apimachinery v0.35.1
|
k8s.io/apimachinery v0.32.1
|
||||||
k8s.io/client-go v0.35.1
|
k8s.io/client-go v0.32.1
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
|
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // 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/structured-merge-diff/v4 v4.4.2 // indirect
|
||||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
277
go.sum
277
go.sum
@@ -1,63 +1,51 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
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.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250604083300-387785b40cb0 h1:iEm/Rf9I0OSCcncuFy61YOSZ3jdRlhJ/oLD97Pc2pCQ=
|
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-20250604083300-387785b40cb0/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250213085018-271cc2caa026/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250620085001-583ca2fbacd5 h1:FEBwueVOOWKYf0tJuE0EKNIbjxmTyCMgkT4qATYsfbo=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250213093249-c53e25e69a7b h1:HAb2h0011mE3QrHdOwJCua5w0r/BDOFLNb/557ZAzL0=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250620085001-583ca2fbacd5/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250213093249-c53e25e69a7b/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250704084459-443546027b27 h1:iogk6pV3gybzQDBXMI6Qd/jvSA1h+3oRE+vLl1MRjew=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250217072519-cafadec1469f h1:esLB0EAn8IuOChW35kcBrPaN80z4A4yYyz1mXT45GQo=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250704084459-443546027b27/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250217072519-cafadec1469f/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250715125819-e735f78e58c6 h1:Gnkv59Ntl2RebC5tNauXuxyRXLfZ2XAJ0+ujMyFte5U=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218080121-a098f0a672ee h1:UIGIiE+O5LUrP18C8nrZxN1v6Lmzfdlv8pvHnSLKJz8=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250715125819-e735f78e58c6/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218080121-a098f0a672ee/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250805113921-40a61387b9f1 h1:53KzZ+1JqRY6J7EVzQpNBmLzNuxb8oHNW3UgqxkYABo=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218085355-6e6ed4ea2c64 h1:dANQHoMCyp3uioCHnUOpLFiG/UO+biyPUoSelDNJ814=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250805113921-40a61387b9f1/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218085355-6e6ed4ea2c64/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250808140536-e7a71188a3b5 h1:bmEG0M99WXWCHsMNUgfYqQNEM0YyN4dXxYV1LCY5EYg=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218092508-b771b5d25ee5 h1:EwoctMKdVG1PJHRcBcRKCxgdAxy+TV1T617vxIZwkio=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250808140536-e7a71188a3b5/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218092508-b771b5d25ee5/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250808141553-f4b0cf5683de h1:s47eEnWRCjBMOxbec5ROHztuwu0Zo7MuXgqWizgkiXU=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218101140-6bf058ab5ca4 h1:7om8VD4ZivHA2BKBwvqM98/a7D+MTwppd2FloNBg1Y4=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250808141553-f4b0cf5683de/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218101140-6bf058ab5ca4/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260113155325-5cdfc28d2f51 h1:jlSEprNaUBe628uP9a9TrJ16Q5Ej6OxHlAKNtrHrN2o=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218113916-04f7537066c1 h1:on0zLtHo1Jj6FvQ/wuJCc/sxfBfgrd2qTFknpDh3wQM=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260113155325-5cdfc28d2f51/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218113916-04f7537066c1/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260114125749-fa5b7543332d h1:6oGSN4Fb+H7LNVbUEN7vaDtWBHZTdd2Y1BkBdZ7MLXE=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218115549-81d3406305c5 h1:DP/XYrxSOc5ORMGvVNqTvFjxLF4cymUW/d3HIZXKDEk=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260114125749-fa5b7543332d/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218115549-81d3406305c5/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260129122033-186ba3e689c7 h1:NRFGRqN+j5g3DrtXMYN5T5XSYICG+OU2DisjBdID3j8=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218130229-7c30633bded0 h1:3EsRmeTz6OWHJETrPObctnGF8WgZtXHfwL2cjyHcfOk=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260129122033-186ba3e689c7/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250218130229-7c30633bded0/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260203074447-30e6c9a6183c h1:c19lIseiUk5Hp+06EowfEbMWH1pK8AC/hvQ4ryWgJtY=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219075511-241c6a5a0861 h1:XqTFKSZ8hXGCJbuu/SBwakpftevg1AKV7hDI50cXNUg=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260203074447-30e6c9a6183c/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219075511-241c6a5a0861/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260203083753-4f28b9b589d6 h1:N+0xkioACl3PNo+MquCIIOL/kSICevg340IYOFGQeOw=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219100312-b4a176667754 h1:7J5EUe/iNS6cT6KVDklpgGH7ak30iEFgWJDEPF6wik4=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260203083753-4f28b9b589d6/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219100312-b4a176667754/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260203150531-ef916fe2d995 h1:ZDRvnzTTNHgMm5hYmseHdEPqQ6rn/4v+P9f/JIxPaNw=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219104152-3ecb0e9d960b h1:DhRqJdw2VePaYVlsh8OUA3zl+76Q0FWwGu+a+3aOf6s=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260203150531-ef916fe2d995/go.mod h1:T0UCxRd8w+qCVVC0NEyDiWIGC5ADwEbQ7hFcvftd4Ks=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219104152-3ecb0e9d960b/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260212123952-403913d8cf13 h1:DNIPQ7C+7wjbj5RUx29wLxuIe/wiSOcuUMlLRIv6Fvs=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219142942-5111c9c8bec7 h1:fh6SzBPenzIxufIIzExtx4jEE4OhFposqn3EbHFr92Q=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260212123952-403913d8cf13/go.mod h1:jmyBwmsac/4V7XPL347qawF60JsBCDmNAMfn/ySXKYo=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20250219142942-5111c9c8bec7/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224093610-a9ebad78f3a8 h1:xoC5PAz1469QxrNm8rrsq5+BtwshEt+L2Nhf90MrqrM=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224093610-a9ebad78f3a8/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224120019-0f6aa1fe7881 h1:1JUGErc+3Runda7iapS5sieH+yFqWrGp+ljv7Kly+hc=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224120019-0f6aa1fe7881/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224122900-d18b031a293a h1:gdr886O31Ai5pEFgJC/mrJMJdhplnQg+UJdZF9mV1n4=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224122900-d18b031a293a/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224130821-ce8ef70516f7 h1:p9uJjMY+QkE4neA+xRmIRtAm9us94EKZqgajDdLOd0Y=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260224130821-ce8ef70516f7/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312082544-d7a8f2adaa5c h1:kBb0dpxyInd4Gs1rriz8mkeKwSCOyomn2ZzWY7YWZqc=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312082544-d7a8f2adaa5c/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312083310-f5e199132416 h1:QHR5pzCI/HUawu8pst5Ggio6WPCUUf8XYjNMVk8kSqo=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312083310-f5e199132416/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312104524-e28b79ac0d62 h1:sHzacZxPIKHyjL4EkgG/c7MI8gM1xmLdhaoUx2ZsH+M=
|
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20260312104524-e28b79ac0d62/go.mod h1:+ENuvBfZdESSvecoqGY/wSvRlT3vinEolxKgwbOhUpA=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
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 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=
|
||||||
github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
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/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 h1:5+Cc1UwaQE5ka3w7R3hxZ1TK3M6VjDEXA5WSQ/IXrxY=
|
||||||
github.com/argoproj/argo-workflows/v3 v3.6.4/go.mod h1:2f5zB8CkbNCCO1od+kd1dWkVokqcuyvu+tc+Jwx1MZg=
|
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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/beego/beego/v2 v2.3.8 h1:wplhB1pF4TxR+2SS4PUej8eDoH4xGfxuHfS7wAk9VBc=
|
github.com/beego/beego/v2 v2.3.1 h1:7MUKMpJYzOXtCUsTEoXOxsDV/UcHw6CPbaWMlthVNsc=
|
||||||
github.com/beego/beego/v2 v2.3.8/go.mod h1:8vl9+RrXqvodrl9C8yivX1e6le6deCK6RWeq8R7gTTg=
|
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
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 h1:MJ+n3+rSxWQdqVJU8eBy9RqcdH6ePPn4PJHocVWUa+Q=
|
||||||
github.com/biter777/countries v1.7.5/go.mod h1:1HSpZ526mYqKJcpT5Ti1kcGQ0L0SrXWIaptUWjFfv2E=
|
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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
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/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/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.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
@@ -71,14 +59,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
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/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 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
|
||||||
github.com/emicklei/go-restful/v3 v3.12.2/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.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.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/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
@@ -87,15 +71,11 @@ github.com/etcd-io/etcd v3.3.17+incompatible/go.mod h1:cdZ77EstHBwVtD6iTgzgvogwc
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
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 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
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 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
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/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 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
|
||||||
@@ -108,10 +88,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
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 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
|
||||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
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/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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@@ -124,17 +102,15 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
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 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
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 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||||
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
|
||||||
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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.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.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
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.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 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
@@ -149,8 +125,8 @@ 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/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 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
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/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/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
@@ -163,25 +139,20 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
|
|||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
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 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
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/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/libp2p/go-libp2p/core v0.43.0-rc2 h1:1X1aDJNWhMfodJ/ynbaGLkgnC8f+hfBIqQDrzxFZOqI=
|
|
||||||
github.com/libp2p/go-libp2p/core v0.43.0-rc2/go.mod h1:NYeJ9lvyBv9nbDk2IuGb8gFKEOkIv/W5YRIy1pAJB2Q=
|
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
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/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 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
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-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
@@ -197,18 +168,14 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||||||
github.com/modern-go/reflect2 v1.0.1/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 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
|
||||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
|
||||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
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/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 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/nats-io/nats.go v1.43.0 h1:uRFZ2FEoRvP64+UUhaTokyS18XBCR/xM2vQZKO4i8ug=
|
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
|
||||||
github.com/nats-io/nats.go v1.43.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
|
||||||
github.com/nats-io/nats.go v1.44.0 h1:ECKVrDLdh/kDPV1g0gAQ+2+m2KprqZK5O/eJAyAnH2M=
|
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||||
github.com/nats-io/nats.go v1.44.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||||
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
|
|
||||||
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
|
|
||||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
github.com/nwtgck/go-fakelish v0.1.3 h1:bA8/xa9hQmzppexIhBvdmztcd/PJ4SPuAUTBdMKZ8G4=
|
github.com/nwtgck/go-fakelish v0.1.3 h1:bA8/xa9hQmzppexIhBvdmztcd/PJ4SPuAUTBdMKZ8G4=
|
||||||
@@ -226,32 +193,26 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||||
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
|
|
||||||
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||||
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
|
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||||
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
|
||||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
|
||||||
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
|
|
||||||
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
|
|
||||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
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/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 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
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/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 h1:v9ezJDHA1XGxViAUSIoO/Id7Fl63u6d0YmsAm+/p2hs=
|
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
|
||||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02/go.mod h1:RF16/A3L0xSa0oSERcnhd8Pu3IXSDZSK2gmGIMsttFE=
|
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 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
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/skarademir/naturalsort v0.0.0-20150715044055-69a5d87bef62/go.mod h1:oIdVclZaltY1Nf7OQUkg1/2jImBJ+ZfKZuDIRSwk3p0=
|
||||||
@@ -292,30 +253,16 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS
|
|||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
|
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||||
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||||
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
|
|
||||||
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
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-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-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-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-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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
|
||||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
|
||||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
|
||||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
|
||||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
|
||||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
|
||||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
|
||||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
@@ -335,20 +282,12 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
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-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.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
|
||||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
|
||||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
|
||||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
|
||||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
|
||||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
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-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-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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -356,14 +295,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
|
||||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
|
||||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
|
||||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -379,42 +312,20 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
|
||||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
|
||||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
|
||||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
|
||||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
|
||||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
|
||||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
|
||||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
|
||||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
|
||||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
|
||||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
|
||||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
|
||||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
|
||||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
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/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
|
||||||
golang.org/x/time v0.9.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-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-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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -449,19 +360,13 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
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 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8=
|
||||||
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
|
||||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
|
||||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
|
||||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
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 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
|
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@@ -475,37 +380,19 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/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 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=
|
||||||
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
|
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
|
||||||
k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q=
|
|
||||||
k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM=
|
|
||||||
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
|
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
|
||||||
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||||
k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU=
|
|
||||||
k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
|
|
||||||
k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=
|
k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=
|
||||||
k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=
|
k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=
|
||||||
k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM=
|
|
||||||
k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA=
|
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
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 h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
|
||||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
|
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
|
||||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
|
|
||||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
|
|
||||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/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 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
|
||||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
|
||||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
|
||||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
|
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/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
|
||||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
|
||||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
|
||||||
|
|||||||
41
inglying-exonts_09_03_2026_104547.yml
Normal file
41
inglying-exonts_09_03_2026_104547.yml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Workflow
|
||||||
|
metadata:
|
||||||
|
name: oc-monitor-inglying-exonts5
|
||||||
|
spec:
|
||||||
|
entrypoint: dag
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: chu-storage-global
|
||||||
|
spec:
|
||||||
|
accessModes: [ReadWriteOnce]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 500Gi
|
||||||
|
templates:
|
||||||
|
- name: dag
|
||||||
|
dag:
|
||||||
|
tasks:
|
||||||
|
- name: chu-analyzer-3957aa22-8141-4346-8bdd-ba7687a41305
|
||||||
|
template: chu-analyzer-3957aa22-8141-4346-8bdd-ba7687a41305
|
||||||
|
dependencies:
|
||||||
|
- chu-statistics-831cbdbb-db94-4864-a181-5361cf8edf12
|
||||||
|
- name: chu-statistics-831cbdbb-db94-4864-a181-5361cf8edf12
|
||||||
|
template: chu-statistics-831cbdbb-db94-4864-a181-5361cf8edf12
|
||||||
|
- name: chu-analyzer-3957aa22-8141-4346-8bdd-ba7687a41305
|
||||||
|
container:
|
||||||
|
image: opencloudregistry/chu-analyzer:latest
|
||||||
|
command: [sh, -c]
|
||||||
|
args: ['echo "chu-analyzer-3957aa22-8141-4346-8bdd-ba7687a41305" && chu-analyzer ']
|
||||||
|
volumeMounts:
|
||||||
|
- name: chu-storage-global
|
||||||
|
mountPath: /data
|
||||||
|
- name: chu-statistics-831cbdbb-db94-4864-a181-5361cf8edf12
|
||||||
|
container:
|
||||||
|
image: opencloudregistry/chu-statistics:latest
|
||||||
|
command: [sh, -c]
|
||||||
|
args: ['echo "chu-statistics-831cbdbb-db94-4864-a181-5361cf8edf12" && chu-statistics ']
|
||||||
|
volumeMounts:
|
||||||
|
- name: chu-storage-global
|
||||||
|
mountPath: /data
|
||||||
|
activeDeadlineSeconds: 3600
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"oc-monitord/tools"
|
|
||||||
"oc-monitord/utils"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
|
|
||||||
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An object to monitor the logs generated by a specific pod from a workflow execution
|
|
||||||
type ArgoWatch struct {
|
|
||||||
Name string
|
|
||||||
Namespace string
|
|
||||||
Status string
|
|
||||||
Conditions
|
|
||||||
Created string
|
|
||||||
Started string
|
|
||||||
Duration string
|
|
||||||
Progress string
|
|
||||||
Logs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conditions struct {
|
|
||||||
PodRunning bool
|
|
||||||
Completed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgoWatch) Equals(arg *ArgoWatch) bool {
|
|
||||||
if arg == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return a.Status == arg.Status && a.Progress == arg.Progress && a.Conditions.PodRunning == arg.Conditions.PodRunning && a.Conditions.Completed == arg.Conditions.Completed
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewArgoLogs(name string, namespace string, stepMax int) *ArgoLogs {
|
|
||||||
return &ArgoLogs{
|
|
||||||
Name: "oc-monitor-" + name,
|
|
||||||
Namespace: namespace,
|
|
||||||
CreatedDate: time.Now().Format("2006-01-02 15:04:05"),
|
|
||||||
StepCount: 0,
|
|
||||||
StepMax: stepMax,
|
|
||||||
stop: false,
|
|
||||||
Seen: []string{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// An object to monitor and log the output of an argo submit
|
|
||||||
type ArgoLogs struct {
|
|
||||||
Name string
|
|
||||||
Namespace string
|
|
||||||
CreatedDate string
|
|
||||||
StepCount int
|
|
||||||
StepMax int
|
|
||||||
stop bool
|
|
||||||
Started time.Time
|
|
||||||
Seen []string
|
|
||||||
Logs []string
|
|
||||||
IsStreaming bool
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArgoPodLog struct {
|
|
||||||
PodName string
|
|
||||||
Step string
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewArgoPodLog(name string, step string, msg string) ArgoPodLog {
|
|
||||||
return ArgoPodLog{
|
|
||||||
PodName: name,
|
|
||||||
Step: step,
|
|
||||||
Message: msg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func LogKubernetesArgo(wfName string, execID string, namespace string, watcher watch.Interface) {
|
|
||||||
var argoWatcher *ArgoWatch
|
|
||||||
var pods []string
|
|
||||||
var node wfv1.NodeStatus
|
|
||||||
|
|
||||||
wfl := utils.GetWFLogger("")
|
|
||||||
wfl.Debug().Msg("Starting to log " + wfName)
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
for event := range watcher.ResultChan() {
|
|
||||||
wf, ok := event.Object.(*wfv1.Workflow)
|
|
||||||
if !ok {
|
|
||||||
wfl.Error().Msg("unexpected type")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(wf.Status.Nodes) == 0 {
|
|
||||||
wfl.Info().Msg("No node status yet") // The first output of the channel doesn't contain Nodes so we skip it
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
conditions := retrieveCondition(wf)
|
|
||||||
|
|
||||||
// Retrieving the Status for the main node, which is named after the workflow
|
|
||||||
if node, ok = wf.Status.Nodes[wfName]; !ok {
|
|
||||||
bytified, _ := json.MarshalIndent(wf.Status.Nodes, "", "\t")
|
|
||||||
wfl.Fatal().Msg("Could not find the " + wfName + " node in \n" + string(bytified))
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
start, _ := time.Parse(time.RFC3339, node.StartedAt.String())
|
|
||||||
duration := now.Sub(start)
|
|
||||||
|
|
||||||
newWatcher := ArgoWatch{
|
|
||||||
Name: node.Name,
|
|
||||||
Namespace: namespace,
|
|
||||||
Status: string(node.Phase),
|
|
||||||
Created: node.StartedAt.String(),
|
|
||||||
Started: node.StartedAt.String(),
|
|
||||||
Progress: string(node.Progress),
|
|
||||||
Duration: duration.String(),
|
|
||||||
Conditions: conditions,
|
|
||||||
}
|
|
||||||
|
|
||||||
if argoWatcher == nil {
|
|
||||||
argoWatcher = &newWatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
if !newWatcher.Equals(argoWatcher) {
|
|
||||||
jsonified, _ := json.Marshal(newWatcher)
|
|
||||||
wfl.Info().Msg(string(jsonified))
|
|
||||||
argoWatcher = &newWatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
// I don't think we need to use WaitGroup here, because the loop itself
|
|
||||||
// acts as blocking process for the main thread, because Argo watch never closes the channel
|
|
||||||
for _, pod := range wf.Status.Nodes {
|
|
||||||
if !slices.Contains(pods, pod.Name) {
|
|
||||||
pl := wfl.With().Str("pod", pod.Name).Logger()
|
|
||||||
if wfName == pod.Name {
|
|
||||||
pods = append(pods, pod.Name)
|
|
||||||
continue
|
|
||||||
} // One of the node is the Workflow, the others are the pods so don't try to log on the wf name
|
|
||||||
pl.Info().Msg("Found a new pod to log : " + pod.Name)
|
|
||||||
wg.Add(1)
|
|
||||||
go logKubernetesPods(namespace, wfName, pod.Name, pl, &wg)
|
|
||||||
pods = append(pods, pod.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop listening to the chan when the Workflow is completed or something bad happened
|
|
||||||
if node.Phase.Completed() {
|
|
||||||
wfl.Info().Msg(wfName + " worflow completed")
|
|
||||||
wg.Wait()
|
|
||||||
wfl.Info().Msg(wfName + " exiting")
|
|
||||||
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), nil).UpdateOne(map[string]interface{}{
|
|
||||||
"state": enum.SUCCESS.EnumIndex(),
|
|
||||||
}, execID)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if node.Phase.FailedOrError() {
|
|
||||||
wfl.Error().Msg(wfName + "has failed, please refer to the logs")
|
|
||||||
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), nil).UpdateOne(map[string]interface{}{
|
|
||||||
"state": enum.FAILURE.EnumIndex(),
|
|
||||||
}, execID)
|
|
||||||
wfl.Error().Msg(node.Message)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func retrieveCondition(wf *wfv1.Workflow) (c Conditions) {
|
|
||||||
for _, cond := range wf.Status.Conditions {
|
|
||||||
if cond.Type == "PodRunning" {
|
|
||||||
c.PodRunning = cond.Status == "True"
|
|
||||||
}
|
|
||||||
if cond.Type == "Completed" {
|
|
||||||
c.Completed = cond.Status == "True"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function needed to be executed as a go thread
|
|
||||||
func logKubernetesPods(executionId string, wfName string, podName string, logger zerolog.Logger, wg *sync.WaitGroup) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
s := strings.Split(podName, ".")
|
|
||||||
name := s[0] + "-" + s[1]
|
|
||||||
step := s[1]
|
|
||||||
|
|
||||||
k, err := tools.NewKubernetesTool()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("Could not get Kubernetes tools")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
reader, err := k.GetPodLogger(executionId, wfName, podName)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(reader)
|
|
||||||
for scanner.Scan() {
|
|
||||||
log := scanner.Text()
|
|
||||||
podLog := NewArgoPodLog(name, step, log)
|
|
||||||
jsonified, _ := json.Marshal(podLog)
|
|
||||||
logger.Info().Msg(string(jsonified))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"oc-monitord/conf"
|
|
||||||
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"cloud.o-forge.io/core/oc-lib/logs"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var logger zerolog.Logger
|
|
||||||
var wfLogger zerolog.Logger
|
|
||||||
|
|
||||||
|
|
||||||
// Take the slice of string that make up one round of stderr outputs from the --watch option in argo submit
|
|
||||||
func NewLocalArgoWatch(inputs []string) *ArgoWatch {
|
|
||||||
var workflow ArgoWatch
|
|
||||||
|
|
||||||
for _, input := range inputs {
|
|
||||||
line := strings.TrimSpace(input)
|
|
||||||
if line == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(line, "Name:"):
|
|
||||||
workflow.Name = parseValue(line)
|
|
||||||
case strings.HasPrefix(line, "Namespace:"):
|
|
||||||
workflow.Namespace = parseValue(line)
|
|
||||||
case strings.HasPrefix(line, "Status:"):
|
|
||||||
workflow.Status = parseValue(line)
|
|
||||||
case strings.HasPrefix(line, "PodRunning"):
|
|
||||||
workflow.PodRunning = parseBoolValue(line)
|
|
||||||
case strings.HasPrefix(line, "Completed"):
|
|
||||||
workflow.Completed = parseBoolValue(line)
|
|
||||||
case strings.HasPrefix(line, "Created:"):
|
|
||||||
workflow.Created = parseValue(line)
|
|
||||||
case strings.HasPrefix(line, "Started:"):
|
|
||||||
workflow.Started = parseValue(line)
|
|
||||||
case strings.HasPrefix(line, "Duration:"):
|
|
||||||
workflow.Duration = parseValue(line)
|
|
||||||
case strings.HasPrefix(line, "Progress:"):
|
|
||||||
workflow.Progress = parseValue(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &workflow
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func parseValue(line string) string {
|
|
||||||
parts := strings.SplitN(line, ":", 2)
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(parts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBoolValue(line string) bool {
|
|
||||||
value := parseValue(line)
|
|
||||||
return value == "True"
|
|
||||||
}
|
|
||||||
|
|
||||||
func LogLocalWorkflow(wfName string, pipe io.ReadCloser, wg *sync.WaitGroup) {
|
|
||||||
logger = logs.GetLogger()
|
|
||||||
|
|
||||||
logger.Debug().Msg("created wf_logger")
|
|
||||||
wfLogger = logger.With().Str("argo_name", wfName).Str("workflow_id", conf.GetConfig().WorkflowID).Str("workflow_execution_id", conf.GetConfig().ExecutionID).Logger()
|
|
||||||
|
|
||||||
var current_watch, previous_watch ArgoWatch
|
|
||||||
|
|
||||||
watch_output := make([]string, 0)
|
|
||||||
scanner := bufio.NewScanner(pipe)
|
|
||||||
for scanner.Scan() {
|
|
||||||
log := scanner.Text()
|
|
||||||
watch_output = append(watch_output, log)
|
|
||||||
|
|
||||||
// Log the progress of the WF
|
|
||||||
if strings.HasPrefix(log, "Progress:") {
|
|
||||||
|
|
||||||
current_watch = *NewLocalArgoWatch(watch_output)
|
|
||||||
workflowName := current_watch.Name
|
|
||||||
if !current_watch.Equals(&previous_watch) {
|
|
||||||
wg.Add(1)
|
|
||||||
// checkStatus(current_watch.Status, previous_watch.Status)
|
|
||||||
jsonified, err := json.Marshal(current_watch)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("Could not create watch log for " + workflowName)
|
|
||||||
}
|
|
||||||
wfLogger.Info().Msg(string(jsonified))
|
|
||||||
previous_watch = current_watch
|
|
||||||
current_watch = ArgoWatch{}
|
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug, no logs sent
|
|
||||||
func LogLocalPod(wfName string, pipe io.ReadCloser, steps []string, wg *sync.WaitGroup) {
|
|
||||||
scanner := bufio.NewScanner(pipe)
|
|
||||||
for scanner.Scan() {
|
|
||||||
var podLogger zerolog.Logger
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
line := scanner.Text()
|
|
||||||
podName := strings.Split(line, ":")[0]
|
|
||||||
podLogger = wfLogger.With().Str("step_name", getStepName(podName, steps)).Logger()
|
|
||||||
log := strings.Split(line,podName+":")[1]
|
|
||||||
podLog := NewArgoPodLog(wfName,podName,log)
|
|
||||||
|
|
||||||
jsonifiedLog, err := json.Marshal(podLog)
|
|
||||||
if err != nil {
|
|
||||||
podLogger.Fatal().Msg(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
podLogger.Info().Msg(string(jsonifiedLog))
|
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStepName(podName string, steps []string) string {
|
|
||||||
|
|
||||||
for _, step := range(steps) {
|
|
||||||
if strings.Contains(podName,step){
|
|
||||||
return step
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "error"
|
|
||||||
}
|
|
||||||
|
|
||||||
217
main.go
217
main.go
@@ -1,14 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"oc-monitord/conf"
|
"oc-monitord/conf"
|
||||||
l "oc-monitord/logger"
|
"oc-monitord/models"
|
||||||
u "oc-monitord/utils"
|
u "oc-monitord/utils"
|
||||||
"oc-monitord/workflow_builder"
|
"oc-monitord/workflow_builder"
|
||||||
|
|
||||||
@@ -16,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"cloud.o-forge.io/core/oc-lib/logs"
|
"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/booking"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/peer"
|
"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/utils"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
||||||
@@ -49,24 +54,25 @@ func main() {
|
|||||||
|
|
||||||
os.Setenv("test_service", "true") // Only for service demo, delete before merging on main
|
os.Setenv("test_service", "true") // Only for service demo, delete before merging on main
|
||||||
parser = *argparse.NewParser("oc-monitord", "Launch the execution of a workflow given as a parameter and sends the produced logs to a loki database")
|
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(&parser)
|
loadConfig(false, &parser)
|
||||||
oclib.InitDaemon("oc-monitord")
|
oclib.InitDaemon("oc-monitord")
|
||||||
|
|
||||||
logger = u.GetLogger()
|
oclib.SetConfig(
|
||||||
|
conf.GetConfig().MongoURL,
|
||||||
|
conf.GetConfig().Database,
|
||||||
|
conf.GetConfig().NatsURL,
|
||||||
|
conf.GetConfig().LokiURL,
|
||||||
|
conf.GetConfig().Logs,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logs.CreateLogger("oc-monitord")
|
||||||
|
|
||||||
logger.Debug().Msg("Loki URL : " + conf.GetConfig().LokiURL)
|
logger.Debug().Msg("Loki URL : " + conf.GetConfig().LokiURL)
|
||||||
logger.Info().Msg("Workflow executed : " + conf.GetConfig().ExecutionID)
|
logger.Debug().Msg("Workflow executed : " + conf.GetConfig().ExecutionID)
|
||||||
exec := u.GetExecution(conf.GetConfig().ExecutionID)
|
exec := u.GetExecution(conf.GetConfig().ExecutionID)
|
||||||
if exec == nil {
|
|
||||||
logger.Fatal().Msg("Could not retrieve workflow ID from execution ID " + conf.GetConfig().ExecutionID + " on peer " + conf.GetConfig().PeerID)
|
|
||||||
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), nil).UpdateOne(map[string]interface{}{
|
|
||||||
"state": enum.FAILURE.EnumIndex(),
|
|
||||||
}, conf.GetConfig().ExecutionID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conf.GetConfig().WorkflowID = exec.WorkflowID
|
conf.GetConfig().WorkflowID = exec.WorkflowID
|
||||||
|
|
||||||
logger.Info().Msg("Starting construction of yaml argo for workflow :" + exec.WorkflowID)
|
logger.Debug().Msg("Starting construction of yaml argo for workflow :" + exec.WorkflowID)
|
||||||
|
|
||||||
if _, err := os.Stat("./argo_workflows/"); os.IsNotExist(err) {
|
if _, err := os.Stat("./argo_workflows/"); os.IsNotExist(err) {
|
||||||
os.Mkdir("./argo_workflows/", 0755)
|
os.Mkdir("./argo_workflows/", 0755)
|
||||||
@@ -81,80 +87,149 @@ func main() {
|
|||||||
logger.Error().Msg("Could not retrieve workflow " + conf.GetConfig().WorkflowID + " from oc-catalog API")
|
logger.Error().Msg("Could not retrieve workflow " + conf.GetConfig().WorkflowID + " from oc-catalog API")
|
||||||
}
|
}
|
||||||
|
|
||||||
builder, _, err := new_wf.ExportToArgo(exec, conf.GetConfig().Timeout) // Removed stepMax so far, I don't know if we need it anymore
|
argo_file_path, stepMax, err := new_wf.ExportToArgo(exec.ExecutionsID, conf.GetConfig().Timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Msg("Could not create the Argo file for " + conf.GetConfig().WorkflowID)
|
logger.Error().Msg("Could not create the Argo file for " + conf.GetConfig().WorkflowID)
|
||||||
logger.Error().Msg(err.Error())
|
logger.Error().Msg(err.Error())
|
||||||
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), nil).UpdateOne(map[string]interface{}{
|
|
||||||
"state": enum.FAILURE.EnumIndex(),
|
|
||||||
}, exec.GetID())
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
logger.Debug().Msg("Created :" + argo_file_path)
|
||||||
|
|
||||||
argoFilePath, err := builder.CompleteBuild(exec.ExecutionsID)
|
workflowName = getContainerName(argo_file_path)
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("Error when completing the build of the workflow: " + err.Error())
|
|
||||||
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), nil).UpdateOne(map[string]interface{}{
|
|
||||||
"state": enum.FAILURE.EnumIndex(),
|
|
||||||
}, exec.GetID())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workflowName = getContainerName(argoFilePath)
|
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")
|
||||||
|
|
||||||
if conf.GetConfig().KubeHost == "" {
|
if conf.GetConfig().KubeHost == "" {
|
||||||
// Not in a k8s environment, get conf from parameters
|
// Not in a k8s environment, get conf from parameters
|
||||||
panic("can't exec with no kube for argo deployment")
|
fmt.Println("Executes outside of k8s")
|
||||||
|
executeOutside(argo_file_path, stepMax)
|
||||||
} else {
|
} else {
|
||||||
// Executed in a k8s environment
|
// Executed in a k8s environment
|
||||||
logger.Info().Msg("Executes inside a k8s")
|
fmt.Println("Executes inside a k8s")
|
||||||
// executeInside(exec.GetID(), "argo", argo_file_path, stepMax) // commenting to use conf.ExecutionID instead of exec.GetID()
|
executeInside(exec.GetID(), "argo", argo_file_path, stepMax)
|
||||||
executeInside(exec.ExecutionsID, exec.GetID(), argoFilePath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// So far we only log the output from
|
// So far we only log the output from
|
||||||
func executeInside(ns string, execID string, argo_file_path string) {
|
func executeInside(execID string, ns string, argo_file_path string, stepMax int) {
|
||||||
t, err := tools2.NewService(conf.GetConfig().Mode)
|
t, err := tools2.NewService(conf.GetConfig().Mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Msg("Could not create KubernetesTool")
|
logger.Error().Msg("Could not create KubernetesTool : " + err.Error())
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := t.CreateArgoWorkflow(argo_file_path, ns)
|
name, err := t.CreateArgoWorkflow(argo_file_path, ns)
|
||||||
// _ = name
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Msg("Could not create argo workflow : " + err.Error())
|
logger.Error().Msg("Could not create argo workflow : " + err.Error())
|
||||||
logger.Info().Msg(fmt.Sprint("CA :" + conf.GetConfig().KubeCA))
|
|
||||||
logger.Info().Msg(fmt.Sprint("Cert :" + conf.GetConfig().KubeCert))
|
|
||||||
logger.Info().Msg(fmt.Sprint("Data :" + conf.GetConfig().KubeData))
|
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
watcher, err := t.GetArgoWatch(ns, workflowName)
|
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 {
|
if err != nil {
|
||||||
logger.Error().Msg("Could not retrieve Watcher : " + err.Error())
|
logger.Error().Msg("Could not log workflow : " + err.Error())
|
||||||
oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), nil).UpdateOne(map[string]interface{}{
|
|
||||||
"state": enum.FAILURE.EnumIndex(),
|
|
||||||
}, execID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.LogKubernetesArgo(name, execID, ns, watcher)
|
|
||||||
logger.Info().Msg("Finished, exiting...")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig(parser *argparse.Parser) {
|
func executeOutside(argo_file_path string, stepMax int) {
|
||||||
var o *onion.Onion
|
// var stdout, stderr, stdout_logs, stderr_logs io.ReadCloser
|
||||||
o = initOnion(o)
|
var stdout, stderr io.ReadCloser
|
||||||
setConf(parser)
|
// var stderr io.ReadCloser
|
||||||
|
var err error
|
||||||
|
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
|
||||||
|
}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
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 !IsValidUUID(conf.GetConfig().ExecutionID) {
|
if err := cmd.Wait(); err != nil {
|
||||||
// logger.Fatal().Msg("Provided ID is not an UUID")
|
wf_logger.Error().Msg("Could not execute argo submit")
|
||||||
// }
|
wf_logger.Error().Msg(err.Error() + bufio.NewScanner(stderr).Text())
|
||||||
|
updateStatus("fatal", "")
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func setConf(parser *argparse.Parser) {
|
// 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,
|
||||||
|
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()
|
||||||
|
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 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, strings.ReplaceAll(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")
|
||||||
|
}
|
||||||
|
if current_watch.Status == "Failed" {
|
||||||
|
wf_logger.Error().Msg(string(jsonified))
|
||||||
|
} else {
|
||||||
|
wf_logger.Info().Msg(string(jsonified))
|
||||||
|
}
|
||||||
|
previous_watch = current_watch
|
||||||
|
current_watch = &models.ArgoWatch{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig(is_k8s bool, parser *argparse.Parser) {
|
||||||
|
var o *onion.Onion
|
||||||
|
o = initOnion(o)
|
||||||
|
setConf(is_k8s, o, parser)
|
||||||
|
|
||||||
|
if !IsValidUUID(conf.GetConfig().ExecutionID) {
|
||||||
|
logger.Fatal().Msg("Provided ID is not an UUID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setConf(is_k8s bool, o *onion.Onion, parser *argparse.Parser) {
|
||||||
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"})
|
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"})
|
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"})
|
execution := parser.String("e", "execution", &argparse.Options{Required: true, Help: "Execution ID of the workflow to request from oc-catalog API"})
|
||||||
@@ -170,11 +245,9 @@ func setConf(parser *argparse.Parser) {
|
|||||||
host := parser.String("H", "host", &argparse.Options{Required: false, Default: "", Help: "Host for the Kubernetes cluster"})
|
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"})
|
port := parser.String("P", "port", &argparse.Options{Required: false, Default: "6443", Help: "Port for the Kubernetes cluster"})
|
||||||
|
|
||||||
// argoHost := parser.String("h", "argoHost", &argparse.Options{Required: false, Default: "", Help: "Host where Argo is running from"}) // can't use -h because its reserved to help
|
|
||||||
|
|
||||||
err := parser.Parse(os.Args)
|
err := parser.Parse(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Info().Msg(parser.Usage(err))
|
fmt.Println(parser.Usage(err))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
conf.GetConfig().Logs = "debug"
|
conf.GetConfig().Logs = "debug"
|
||||||
@@ -189,8 +262,6 @@ func setConf(parser *argparse.Parser) {
|
|||||||
conf.GetConfig().KubeHost = *host
|
conf.GetConfig().KubeHost = *host
|
||||||
conf.GetConfig().KubePort = *port
|
conf.GetConfig().KubePort = *port
|
||||||
|
|
||||||
// conf.GetConfig().ArgoHost = *argoHost
|
|
||||||
|
|
||||||
decoded, err := base64.StdEncoding.DecodeString(*ca)
|
decoded, err := base64.StdEncoding.DecodeString(*ca)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
conf.GetConfig().KubeCA = string(decoded)
|
conf.GetConfig().KubeCA = string(decoded)
|
||||||
@@ -243,10 +314,30 @@ func getContainerName(argo_file string) string {
|
|||||||
re := regexp.MustCompile(regex)
|
re := regexp.MustCompile(regex)
|
||||||
|
|
||||||
container_name := re.FindString(argo_file)
|
container_name := re.FindString(argo_file)
|
||||||
|
|
||||||
return container_name
|
return container_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uses the ArgoWatch object to update status of the workflow execution object
|
||||||
|
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, log string) {
|
func updateStatus(status string, log string) {
|
||||||
exec_id := conf.GetConfig().ExecutionID
|
exec_id := conf.GetConfig().ExecutionID
|
||||||
|
|
||||||
@@ -254,7 +345,7 @@ func updateStatus(status string, log string) {
|
|||||||
wf_exec.ArgoStatusToState(status)
|
wf_exec.ArgoStatusToState(status)
|
||||||
exec, _, err := workflow_execution.NewAccessor(&tools.APIRequest{
|
exec, _, err := workflow_execution.NewAccessor(&tools.APIRequest{
|
||||||
PeerID: conf.GetConfig().PeerID,
|
PeerID: conf.GetConfig().PeerID,
|
||||||
}).UpdateOne(wf_exec.Serialize(wf_exec), exec_id)
|
}).UpdateOne(wf_exec, exec_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Msg("Could not update status for workflow execution " + exec_id + err.Error())
|
logger.Error().Msg("Could not update status for workflow execution " + exec_id + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
# Goal
|
|
||||||
|
|
||||||
We want to be able to instantiate a service that allows to store file located on a `processing` pod onto it.
|
|
||||||
|
|
||||||
We have already tested it with a static `Argo` yaml file, a MinIO running on the same kubernetes node, the minio service is reached because it is the only associated to the `serviceAccount`.
|
|
||||||
|
|
||||||
We have established three otpions that need to be available to the user for the feature to be implemented:
|
|
||||||
|
|
||||||
- Use a MinIO running constantly on the node that executes the argo workflow
|
|
||||||
- Use a MinIO
|
|
||||||
- A MinIO is instanciated when a new workflow is launched
|
|
||||||
|
|
||||||
# Requirements
|
|
||||||
|
|
||||||
- Helm : `https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3`
|
|
||||||
- Helm GO client : `$ go get github.com/mittwald/go-helm-client`
|
|
||||||
- MinIO chart : `https://charts.min.io/`
|
|
||||||
|
|
||||||
|
|
||||||
# Ressources
|
|
||||||
|
|
||||||
We need to create several ressources in order for the pods to communicate with the MinIO
|
|
||||||
|
|
||||||
## MinIO Auth Secrets
|
|
||||||
|
|
||||||
## Bucket ConfigMap
|
|
||||||
|
|
||||||
With the name `artifact-repositories` this configMap will be used by default. It contains the URL to the MinIO server and the key to the authentication data held in a `secret` ressource.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
# If you want to use this config map by default, name it "artifact-repositories".
|
|
||||||
name: artifact-repositories
|
|
||||||
# annotations:
|
|
||||||
# # v3.0 and after - if you want to use a specific key, put that key into this annotation.
|
|
||||||
# workflows.argoproj.io/default-artifact-repository: oc-s3-artifact-repository
|
|
||||||
data:
|
|
||||||
oc-s3-artifact-repository: |
|
|
||||||
s3:
|
|
||||||
bucket: oc-bucket
|
|
||||||
endpoint: [ retrieve cluster with kubectl get service argo-artifacts -o jsonpath="{.spec.clusterIP}" ]:9000
|
|
||||||
insecure: true
|
|
||||||
accessKeySecret:
|
|
||||||
name: argo-artifact-secret
|
|
||||||
key: access-key
|
|
||||||
secretKeySecret:
|
|
||||||
name: argo-artifact-secret
|
|
||||||
key: secret-key
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# Code modifications
|
|
||||||
|
|
||||||
Rajouter un attribut "isDataLink"
|
|
||||||
- true/false
|
|
||||||
|
|
||||||
Rajouter un attribut DataPath ou un truc comme ca
|
|
||||||
|
|
||||||
- liste de map[string]string permet de n'avoir qu'une copie par fichier)
|
|
||||||
- éditable uniquement a travers la méthode addDataPath
|
|
||||||
- clé : path du fichier / value : nom de la copie dans minio
|
|
||||||
|
|
||||||
===> on a besoin du meme attribut pour Processing -> Data et Data -> Processing
|
|
||||||
145
models/argo_logs.go
Normal file
145
models/argo_logs.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/acarl005/stripansi"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ArgoWatch struct {
|
||||||
|
Name string
|
||||||
|
Namespace string
|
||||||
|
Status string
|
||||||
|
Conditions
|
||||||
|
Created string
|
||||||
|
Started string
|
||||||
|
Duration string
|
||||||
|
Progress string
|
||||||
|
Logs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conditions struct {
|
||||||
|
PodRunning bool
|
||||||
|
Completed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArgoWatch) Equals(arg *ArgoWatch) bool {
|
||||||
|
if arg == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.Status == arg.Status && a.Progress == arg.Progress && a.Conditions.PodRunning == arg.Conditions.PodRunning && a.Conditions.Completed == arg.Conditions.Completed
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewArgoLogs(name string, namespace string, stepMax int) *ArgoLogs {
|
||||||
|
return &ArgoLogs{
|
||||||
|
Name: "oc-monitor-" + name,
|
||||||
|
Namespace: namespace,
|
||||||
|
CreatedDate: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
StepCount: 0,
|
||||||
|
StepMax: stepMax,
|
||||||
|
stop: false,
|
||||||
|
Seen: []string{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArgoLogs struct {
|
||||||
|
Name string
|
||||||
|
Namespace string
|
||||||
|
CreatedDate string
|
||||||
|
StepCount int
|
||||||
|
StepMax int
|
||||||
|
stop bool
|
||||||
|
Started time.Time
|
||||||
|
Seen []string
|
||||||
|
Logs []string
|
||||||
|
IsStreaming bool
|
||||||
|
}
|
||||||
|
|
||||||
|
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(current *ArgoWatch) *ArgoWatch {
|
||||||
|
fn := strings.Split(a.Name, "_")
|
||||||
|
logs := []string{}
|
||||||
|
err := false
|
||||||
|
end := ""
|
||||||
|
for _, input := range current.Logs {
|
||||||
|
line := strings.TrimSpace(input)
|
||||||
|
if line == "" || !strings.Contains(line, fn[0]) || !strings.Contains(line, ":") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
step := strings.Split(line, ":")
|
||||||
|
if strings.Contains(line, "sub-process exited") {
|
||||||
|
b := strings.Split(line, "time=\"")
|
||||||
|
if len(b) > 1 {
|
||||||
|
end = b[1][:19]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(step) < 2 || strings.Contains(line, "time=") || strings.TrimSpace(strings.Join(step[1:], " : ")) == "" || strings.TrimSpace(strings.Join(step[1:], " : ")) == a.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log := stripansi.Strip(strings.TrimSpace(strings.Join(step[1:], " : ")))
|
||||||
|
t, e := strconv.Unquote(log)
|
||||||
|
if e == nil {
|
||||||
|
logs = append(logs, t)
|
||||||
|
} else {
|
||||||
|
logs = append(logs, strings.ReplaceAll(log, "\"", "`"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(logs[len(logs)-1], "Error") {
|
||||||
|
err = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status := "Pending"
|
||||||
|
if a.StepCount > 0 {
|
||||||
|
status = "Running"
|
||||||
|
}
|
||||||
|
if a.StepCount == a.StepMax {
|
||||||
|
if err {
|
||||||
|
status = "Failed"
|
||||||
|
} else {
|
||||||
|
status = "Succeeded"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
duration := float64(0)
|
||||||
|
if end != "" {
|
||||||
|
timeE, _ := time.Parse("2006-01-02T15:04:05", end)
|
||||||
|
duration = timeE.Sub(a.Started).Seconds()
|
||||||
|
}
|
||||||
|
current.Conditions = Conditions{
|
||||||
|
PodRunning: a.StepCount > 0 && a.StepCount < a.StepMax,
|
||||||
|
Completed: a.StepCount == a.StepMax,
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"oc-monitord/conf"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/common/models"
|
"cloud.o-forge.io/core/oc-lib/models/common/models"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/resources"
|
"cloud.o-forge.io/core/oc-lib/models/resources"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/resources/native_tools"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Parameter struct {
|
type Parameter struct {
|
||||||
@@ -64,8 +57,7 @@ type Dag struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TemplateMetadata struct {
|
type TemplateMetadata struct {
|
||||||
Labels map[string]string `yaml:"labels,omitempty"`
|
Labels map[string]string `yaml:"labels,omitempty"`
|
||||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Secret struct {
|
type Secret struct {
|
||||||
@@ -78,18 +70,14 @@ type Key struct {
|
|||||||
Bucket string `yaml:"bucket"`
|
Bucket string `yaml:"bucket"`
|
||||||
EndPoint string `yaml:"endpoint"`
|
EndPoint string `yaml:"endpoint"`
|
||||||
Insecure bool `yaml:"insecure"`
|
Insecure bool `yaml:"insecure"`
|
||||||
AccessKeySecret *Secret `yaml:"accessKeySecret"`
|
AccessKeySecret *Secret `yaml accessKeySecret`
|
||||||
SecretKeySecret *Secret `yaml:"secretKeySecret"`
|
SecretKeySecret *Secret `yaml secretKeySecret`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Artifact struct {
|
type Artifact struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Path string `yaml:"path"`
|
Path string `yaml:"path"`
|
||||||
}
|
S3 *Key `yaml:"s3,omitempty"`
|
||||||
|
|
||||||
type ArtifactRepositoryRef struct {
|
|
||||||
ConfigMap string `yaml:"configMap"`
|
|
||||||
Key string `yaml:"key"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type InOut struct {
|
type InOut struct {
|
||||||
@@ -107,54 +95,8 @@ type Template struct {
|
|||||||
Resource ServiceResource `yaml:"resource,omitempty"`
|
Resource ServiceResource `yaml:"resource,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (template *Template) CreateEventContainer(execution *workflow_execution.WorkflowExecution, nt *resources.NativeTool, dag *Dag) {
|
func (template *Template) CreateContainer(processing *resources.ProcessingResource, dag *Dag, templateName string) {
|
||||||
container := Container{Image: "natsio/nats-box"}
|
instance := processing.GetSelectedInstance()
|
||||||
container.Command = []string{"sh", "-c"} // all is bash
|
|
||||||
|
|
||||||
var event native_tools.WorkflowEventParams
|
|
||||||
b, err := json.Marshal(nt.Params)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(b, &event)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if event.WorkflowResourceID != "" {
|
|
||||||
event.Payload = event.Input
|
|
||||||
event.Input = ""
|
|
||||||
if b, err := json.Marshal(event); err == nil {
|
|
||||||
payload, err := json.Marshal(&tools.NATSResponse{
|
|
||||||
FromApp: "oc-monitord",
|
|
||||||
Datatype: tools.NATIVE_TOOL,
|
|
||||||
Method: int(tools.WORKFLOW_EVENT),
|
|
||||||
Payload: b,
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
cmd := exec.Command(
|
|
||||||
"nats",
|
|
||||||
"pub",
|
|
||||||
"--server", conf.GetConfig().NatsURL+":4222",
|
|
||||||
tools.WORKFLOW_EVENT.GenerateKey(),
|
|
||||||
string(payload),
|
|
||||||
)
|
|
||||||
for _, args := range cmd.Args {
|
|
||||||
container.Args = append(container.Args, args)
|
|
||||||
}
|
|
||||||
template.Container = container
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (template *Template) CreateContainer(exec *workflow_execution.WorkflowExecution, processing *resources.ProcessingResource, dag *Dag) {
|
|
||||||
index := 0
|
|
||||||
if d, ok := exec.SelectedInstances[processing.GetID()]; ok {
|
|
||||||
index = d
|
|
||||||
}
|
|
||||||
instance := processing.GetSelectedInstance(&index)
|
|
||||||
if instance == nil {
|
if instance == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -174,7 +116,7 @@ func (template *Template) CreateContainer(exec *workflow_execution.WorkflowExecu
|
|||||||
template.Outputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name})
|
template.Outputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name})
|
||||||
}
|
}
|
||||||
cmd := strings.ReplaceAll(inst.Access.Container.Command, container.Image, "")
|
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, " ") {
|
for _, a := range strings.Split(cmd, " ") {
|
||||||
container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env))
|
container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env))
|
||||||
}
|
}
|
||||||
@@ -182,13 +124,12 @@ func (template *Template) CreateContainer(exec *workflow_execution.WorkflowExecu
|
|||||||
container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env))
|
container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env))
|
||||||
}
|
}
|
||||||
container.Args = []string{strings.Join(container.Args, " ")}
|
container.Args = []string{strings.Join(container.Args, " ")}
|
||||||
|
|
||||||
template.Container = container
|
template.Container = container
|
||||||
}
|
}
|
||||||
|
|
||||||
func (template *Template) ReplacePerEnv(arg string, envs []models.Param) string {
|
func (template *Template) ReplacePerEnv(arg string, envs []models.Param) string {
|
||||||
for _, v := range envs {
|
for _, v := range envs {
|
||||||
if v.Name != "" && strings.Contains(arg, v.Name) {
|
if strings.Contains(arg, v.Name) {
|
||||||
value := "{{ inputs.parameters." + 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, "$"+v.Name, value)
|
arg = strings.ReplaceAll(arg, "$"+v.Name, value)
|
||||||
@@ -197,13 +138,3 @@ func (template *Template) ReplacePerEnv(arg string, envs []models.Param) string
|
|||||||
}
|
}
|
||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the metadata that allow Admiralty to pick up an Argo Workflow that needs to be reparted
|
|
||||||
// The value of "clustername" is the peerId, which must be replaced by the node name's for this specific execution
|
|
||||||
func (t *Template) AddAdmiraltyAnnotations(peerId string) {
|
|
||||||
if t.Metadata.Annotations == nil {
|
|
||||||
t.Metadata.Annotations = make(map[string]string)
|
|
||||||
}
|
|
||||||
t.Metadata.Annotations["multicluster.admiralty.io/elect"] = ""
|
|
||||||
t.Metadata.Annotations["multicluster.admiralty.io/clustername"] = peerId
|
|
||||||
}
|
|
||||||
|
|||||||
BIN
oc-monitord
BIN
oc-monitord
Binary file not shown.
@@ -3,17 +3,17 @@ package tools
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"oc-monitord/models"
|
||||||
v1 "k8s.io/api/core/v1"
|
"sync"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tool interface {
|
type Tool interface {
|
||||||
CreateArgoWorkflow(path string, ns string) (string, error)
|
CreateArgoWorkflow(path string, ns string) (string, error)
|
||||||
CreateAccessSecret(user string, password string, storageId string, namespace string) (string, error)
|
CreateAccessSecret(ns string, login string, password string) (string, error)
|
||||||
GetArgoWatch(executionId string, wfName string) (watch.Interface, error)
|
LogWorkflow(execID string, namespace string, workflowName string, argoFilePath string, stepMax int, current_watch *models.ArgoWatch, previous_watch *models.ArgoWatch,
|
||||||
GetPodLogger(ns string, wfName string, podName string) (io.ReadCloser, error)
|
argoLogs *models.ArgoLogs, seen []string,
|
||||||
GetS3Secret(storageId string, namespace string) *v1.Secret
|
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){
|
var _service = map[string]func() (Tool, error){
|
||||||
|
|||||||
@@ -2,22 +2,26 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"oc-monitord/conf"
|
"oc-monitord/conf"
|
||||||
|
"oc-monitord/models"
|
||||||
"oc-monitord/utils"
|
"oc-monitord/utils"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
||||||
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
|
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
|
||||||
"github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned"
|
"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"
|
v1 "k8s.io/api/core/v1"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
@@ -28,9 +32,10 @@ type KubernetesTools struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewKubernetesTool() (Tool, error) {
|
func NewKubernetesTool() (Tool, error) {
|
||||||
|
fmt.Println(conf.GetConfig().KubeCA, conf.GetConfig().KubeCert, conf.GetConfig().KubeData)
|
||||||
// Load Kubernetes config (from ~/.kube/config)
|
// Load Kubernetes config (from ~/.kube/config)
|
||||||
config := &rest.Config{
|
config := &rest.Config{
|
||||||
Host: "https://" + conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort,
|
Host: conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort,
|
||||||
TLSClientConfig: rest.TLSClientConfig{
|
TLSClientConfig: rest.TLSClientConfig{
|
||||||
CAData: []byte(conf.GetConfig().KubeCA),
|
CAData: []byte(conf.GetConfig().KubeCA),
|
||||||
CertData: []byte(conf.GetConfig().KubeCert),
|
CertData: []byte(conf.GetConfig().KubeCert),
|
||||||
@@ -48,13 +53,76 @@ func NewKubernetesTool() (Tool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Error creating Kubernetes versionned client: " + err.Error())
|
return nil, errors.New("Error creating Kubernetes versionned client: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &KubernetesTools{
|
return &KubernetesTools{
|
||||||
Set: clientset,
|
Set: clientset,
|
||||||
VersionedSet: clientset2,
|
VersionedSet: clientset2,
|
||||||
}, nil
|
}, 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.DRAFT || exec.State == enum.FAILURE || exec.State == enum.SUCCESS {
|
||||||
|
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) {
|
func (k *KubernetesTools) CreateArgoWorkflow(path string, ns string) (string, error) {
|
||||||
// Read workflow YAML file
|
// Read workflow YAML file
|
||||||
workflowYAML, err := os.ReadFile(path)
|
workflowYAML, err := os.ReadFile(path)
|
||||||
@@ -78,127 +146,37 @@ func (k *KubernetesTools) CreateArgoWorkflow(path string, ns string) (string, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the workflow in the "argo" namespace
|
// Create the workflow in the "argo" namespace
|
||||||
createdWf, err := k.VersionedSet.ArgoprojV1alpha1().Workflows(ns).Create(context.TODO(), workflow, metav1.CreateOptions{})
|
createdWf, err := k.VersionedSet.ArgoprojV1alpha1().Workflows(ns).Create(context.Background(), workflow, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("failed to create workflow: " + err.Error())
|
return "", errors.New("failed to create workflow: " + err.Error())
|
||||||
}
|
}
|
||||||
l := utils.GetLogger()
|
fmt.Printf("workflow %s created in namespace %s\n", createdWf.Name, "argo")
|
||||||
l.Info().Msg(fmt.Sprintf("workflow %s created in namespace %s\n", createdWf.Name, ns))
|
|
||||||
return createdWf.Name, nil
|
return createdWf.Name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KubernetesTools) CreateAccessSecret(access string, password string, storageId string, namespace string) (string, error) {
|
func (k *KubernetesTools) CreateAccessSecret(ns string, login string, password string) (string, error) {
|
||||||
// Namespace where the secret will be created
|
// Namespace where the secret will be created
|
||||||
|
namespace := "default"
|
||||||
// Encode the secret data (Kubernetes requires base64-encoded values)
|
// Encode the secret data (Kubernetes requires base64-encoded values)
|
||||||
secretData := map[string][]byte{
|
secretData := map[string][]byte{
|
||||||
"access-key": []byte(access),
|
"access-key": []byte(base64.StdEncoding.EncodeToString([]byte(login))),
|
||||||
"secret-key": []byte(password),
|
"secret-key": []byte(base64.StdEncoding.EncodeToString([]byte(password))),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the Secret object
|
// Define the Secret object
|
||||||
name := storageId+"-secret-s3"
|
name := uuid.New().String()
|
||||||
secret := &v1.Secret{
|
secret := &v1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
Namespace: namespace,
|
Namespace: ns,
|
||||||
},
|
},
|
||||||
Type: v1.SecretTypeOpaque,
|
Type: v1.SecretTypeOpaque,
|
||||||
Data: secretData,
|
Data: secretData,
|
||||||
}
|
}
|
||||||
// Create the Secret in Kubernetes
|
// Create the Secret in Kubernetes
|
||||||
_, err := k.Set.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
|
_, err := k.Set.CoreV1().Secrets(namespace).Create(context.Background(), secret, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("Error creating secret: " + err.Error())
|
return "", errors.New("Error creating secret: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return name, nil
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KubernetesTools) GetS3Secret(storageId string, namespace string) *v1.Secret {
|
|
||||||
|
|
||||||
secret, err := k.Set.CoreV1().Secrets(namespace).Get(context.TODO(), storageId + "-secret-s3", metav1.GetOptions{})
|
|
||||||
// Get(context.TODO(),storageId + "-artifact-server", metav1.GetOptions{})
|
|
||||||
|
|
||||||
if err != nil && !k8serrors.IsNotFound(err) {
|
|
||||||
l := utils.GetLogger()
|
|
||||||
l.Fatal().Msg("An error happened when retrieving secret in " + namespace + " : " + err.Error())
|
|
||||||
}
|
|
||||||
if k8serrors.IsNotFound(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return secret
|
|
||||||
// return secret
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (k *KubernetesTools) GetArgoWatch(executionId string, wfName string) (watch.Interface, error){
|
|
||||||
options := metav1.ListOptions{FieldSelector: "metadata.name=oc-monitor-"+wfName}
|
|
||||||
|
|
||||||
watcher, err := k.VersionedSet.ArgoprojV1alpha1().Workflows(executionId).Watch(context.Background(), options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Error executing 'argo watch " + wfName + " -n " + executionId + " with ArgoprojV1alpha1 client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return watcher, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KubernetesTools) GetPodLogger(ns string, wfName string, nodeName string) (io.ReadCloser, error) {
|
|
||||||
var targetPod v1.Pod
|
|
||||||
|
|
||||||
|
|
||||||
pods, err := k.Set.CoreV1().Pods(ns).List(context.Background(), metav1.ListOptions{
|
|
||||||
LabelSelector: "workflows.argoproj.io/workflow="+wfName,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list pods: " + err.Error())
|
|
||||||
}
|
|
||||||
if len(pods.Items) == 0 {
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("no pods found with label workflows.argoproj.io/workflow="+ wfName + " no pods found with label workflows.argoproj.io/node-name=" + nodeName + " in namespace " + ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pod := range pods.Items {
|
|
||||||
if pod.Annotations["workflows.argoproj.io/node-name"] == nodeName {
|
|
||||||
targetPod = pod
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// k8s API throws an error if we try getting logs while the container are not initialized, so we repeat status check there
|
|
||||||
k.testPodReady(targetPod, ns)
|
|
||||||
|
|
||||||
// When using kubec logs for a pod we see it contacts /api/v1/namespaces/NAMESPACE/pods/oc-monitor-PODNAME/log?container=main so we add this container: main to the call
|
|
||||||
req, err := k.Set.CoreV1().Pods(ns).GetLogs(targetPod.Name, &v1.PodLogOptions{Follow: true, Container: "main"}). Stream(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(" Error when trying to get logs for " + targetPod.Name + " : " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KubernetesTools) testPodReady(pod v1.Pod, ns string) {
|
|
||||||
for {
|
|
||||||
pod, err := k.Set.CoreV1().Pods(ns).Get(context.Background(), pod.Name, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
wfl := utils.GetWFLogger("")
|
|
||||||
wfl.Error().Msg("Error fetching pod: " + err.Error() + "\n")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
var initialized bool
|
|
||||||
for _, cond := range pod.Status.Conditions {
|
|
||||||
// It seems that for remote pods the pod gets the Succeeded status before it has time to display the it is ready to run in .status.conditions,so we added the OR condition
|
|
||||||
if (cond.Type == v1.PodReady && cond.Status == v1.ConditionTrue) || pod.Status.Phase == v1.PodSucceeded {
|
|
||||||
initialized = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if initialized {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second) // avoid hammering the API
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,46 +2,17 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"oc-monitord/conf"
|
"oc-monitord/conf"
|
||||||
"sync"
|
|
||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
"cloud.o-forge.io/core/oc-lib/logs"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
logger zerolog.Logger
|
|
||||||
wf_logger zerolog.Logger
|
|
||||||
pods_logger zerolog.Logger
|
|
||||||
onceLogger sync.Once
|
|
||||||
onceWF sync.Once
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetExecution(exec_id string) *workflow_execution.WorkflowExecution {
|
func GetExecution(exec_id string) *workflow_execution.WorkflowExecution {
|
||||||
res := oclib.NewRequest(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), "", conf.GetConfig().PeerID, []string{}, nil).LoadOne(exec_id)
|
res := oclib.NewRequest(oclib.LibDataEnum(oclib.WORKFLOW_EXECUTION), "", conf.GetConfig().PeerID, []string{}, nil).LoadOne(exec_id)
|
||||||
if res.Code != 200 {
|
if res.Code != 200 {
|
||||||
logger := oclib.GetLogger()
|
logger := oclib.GetLogger()
|
||||||
logger.Error().Msg("Error retrieving execution " + exec_id)
|
logger.Error().Msg("Could not retrieve workflow ID from execution ID " + exec_id)
|
||||||
logger.Error().Msg(res.Err)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return res.ToWorkflowExecution()
|
return res.ToWorkflowExecution()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLogger() zerolog.Logger {
|
|
||||||
onceLogger.Do(func(){
|
|
||||||
logger = logs.CreateLogger("oc-monitord")
|
|
||||||
})
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetWFLogger(workflowName string) zerolog.Logger {
|
|
||||||
onceWF.Do(func(){
|
|
||||||
wf_logger = logger.With().
|
|
||||||
Str("argo_name", workflowName).
|
|
||||||
Str("workflow_id", conf.GetConfig().
|
|
||||||
WorkflowID).Str("workflow_execution_id", conf.GetConfig().ExecutionID).Logger()
|
|
||||||
})
|
|
||||||
return wf_logger
|
|
||||||
}
|
|
||||||
@@ -1,57 +1,38 @@
|
|||||||
// Package workflow_builder traduit les informations du graphe d'un Workflow
|
// A class that translates the informations held in the graph object
|
||||||
// (ses composants, ses liens) en un fichier YAML Argo Workflow prêt à être
|
// via its lists of components into an argo file, using the a list of
|
||||||
// soumis à un cluster Kubernetes. Le point d'entrée principal est ArgoBuilder.
|
// link ID to build the dag
|
||||||
|
|
||||||
package workflow_builder
|
package workflow_builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"oc-monitord/conf"
|
"oc-monitord/conf"
|
||||||
. "oc-monitord/models"
|
. "oc-monitord/models"
|
||||||
|
tools2 "oc-monitord/tools"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
oclib_config "cloud.o-forge.io/core/oc-lib/config"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/logs"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/peer"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/resources"
|
"cloud.o-forge.io/core/oc-lib/models/resources"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/resources/native_tools"
|
"cloud.o-forge.io/core/oc-lib/models/workflow"
|
||||||
w "cloud.o-forge.io/core/oc-lib/models/workflow"
|
w "cloud.o-forge.io/core/oc-lib/models/workflow"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow/graph"
|
"cloud.o-forge.io/core/oc-lib/models/workflow/graph"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
|
||||||
"github.com/nats-io/nats.go"
|
|
||||||
"github.com/nwtgck/go-fakelish"
|
"github.com/nwtgck/go-fakelish"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// logger est le logger zerolog partagé au sein du package, initialisé à
|
|
||||||
// chaque appel de CreateDAG pour récupérer la configuration courante.
|
|
||||||
var logger zerolog.Logger
|
var logger zerolog.Logger
|
||||||
|
|
||||||
// ArgoBuilder est le constructeur principal du fichier Argo Workflow.
|
|
||||||
// Il porte l'état de la construction (workflow source, templates générés,
|
|
||||||
// services k8s à créer, timeout global, liste des peers distants impliqués).
|
|
||||||
type ArgoBuilder struct {
|
type ArgoBuilder struct {
|
||||||
// OriginWorkflow est le workflow métier Open Cloud dont on construit la représentation Argo.
|
|
||||||
OriginWorkflow *w.Workflow
|
OriginWorkflow *w.Workflow
|
||||||
// Workflow est la structure YAML Argo en cours de construction.
|
Workflow Workflow
|
||||||
Workflow Workflow
|
Services []*Service
|
||||||
// Services liste les services Kubernetes à exposer pour les processings "IsService".
|
Timeout int
|
||||||
Services []*Service
|
|
||||||
// Timeout est la durée maximale d'exécution en secondes (activeDeadlineSeconds).
|
|
||||||
Timeout int
|
|
||||||
// RemotePeers contient les IDs des peers distants détectés via Admiralty.
|
|
||||||
RemotePeers []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workflow est la structure racine du fichier YAML Argo Workflow.
|
|
||||||
// Elle correspond exactement au format attendu par le contrôleur Argo.
|
|
||||||
type Workflow struct {
|
type Workflow struct {
|
||||||
ApiVersion string `yaml:"apiVersion"`
|
ApiVersion string `yaml:"apiVersion"`
|
||||||
Kind string `yaml:"kind"`
|
Kind string `yaml:"kind"`
|
||||||
@@ -61,8 +42,6 @@ type Workflow struct {
|
|||||||
Spec Spec `yaml:"spec,omitempty"`
|
Spec Spec `yaml:"spec,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDag retourne le pointeur sur le template "dag" du workflow.
|
|
||||||
// S'il n'existe pas encore, il est créé et ajouté à la liste des templates.
|
|
||||||
func (b *Workflow) getDag() *Dag {
|
func (b *Workflow) getDag() *Dag {
|
||||||
for _, t := range b.Spec.Templates {
|
for _, t := range b.Spec.Templates {
|
||||||
if t.Name == "dag" {
|
if t.Name == "dag" {
|
||||||
@@ -73,95 +52,67 @@ func (b *Workflow) getDag() *Dag {
|
|||||||
return b.Spec.Templates[len(b.Spec.Templates)-1].Dag
|
return b.Spec.Templates[len(b.Spec.Templates)-1].Dag
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spec contient la spécification complète du workflow Argo :
|
|
||||||
// compte de service, point d'entrée, volumes, templates et timeout.
|
|
||||||
type Spec struct {
|
type Spec struct {
|
||||||
ArtifactRepositoryRef
|
Entrypoint string `yaml:"entrypoint"`
|
||||||
ServiceAccountName string `yaml:"serviceAccountName,omitempty"`
|
Arguments []Parameter `yaml:"arguments,omitempty"`
|
||||||
Entrypoint string `yaml:"entrypoint"`
|
Volumes []VolumeClaimTemplate `yaml:"volumeClaimTemplates,omitempty"`
|
||||||
Arguments []Parameter `yaml:"arguments,omitempty"`
|
Templates []Template `yaml:"templates"`
|
||||||
Volumes []VolumeClaimTemplate `yaml:"volumeClaimTemplates,omitempty"`
|
Timeout int `yaml:"activeDeadlineSeconds,omitempty"`
|
||||||
Templates []Template `yaml:"templates"`
|
|
||||||
Timeout int `yaml:"activeDeadlineSeconds,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateDAG est le point d'entrée de la construction du DAG Argo.
|
// TODO: found on a processing instance linked to storage
|
||||||
// Il crée tous les templates (un par processing / native tool / sous-workflow),
|
// add s3, gcs, azure, etc if needed on a link between processing and storage
|
||||||
// configure les volumes persistants, positionne les métadonnées globales du
|
func (b *ArgoBuilder) CreateDAG(namespace string, write bool) (string, int, []string, []string, error) {
|
||||||
// workflow et retourne :
|
fmt.Println("Creating DAG", b.OriginWorkflow.Graph.Items)
|
||||||
// - le nombre de tâches dans le DAG,
|
// handle services by checking if there is only one processing with hostname and port
|
||||||
// - les noms des premières tâches (sans dépendances),
|
firstItems, lastItems, volumes := b.createTemplates(namespace)
|
||||||
// - les noms des dernières tâches (dont personne ne dépend),
|
b.createVolumes(volumes)
|
||||||
// - une éventuelle erreur.
|
|
||||||
//
|
|
||||||
// Le paramètre write est conservé pour usage futur (écriture effective du YAML).
|
|
||||||
// TODO: gérer S3, GCS, Azure selon le type de stockage lié au processing.
|
|
||||||
func (b *ArgoBuilder) CreateDAG(exec *workflow_execution.WorkflowExecution, namespace string, write bool) (int, []string, []string, error) {
|
|
||||||
logger = logs.GetLogger()
|
|
||||||
logger.Info().Msg(fmt.Sprint("Creating DAG ", b.OriginWorkflow.Graph.Items))
|
|
||||||
// Crée un template Argo pour chaque nœud du graphe et collecte les volumes.
|
|
||||||
firstItems, lastItems, volumes := b.createTemplates(exec, namespace)
|
|
||||||
b.createVolumes(exec, volumes)
|
|
||||||
|
|
||||||
if b.Timeout > 0 {
|
if b.Timeout > 0 {
|
||||||
b.Workflow.Spec.Timeout = b.Timeout
|
b.Workflow.Spec.Timeout = b.Timeout
|
||||||
}
|
}
|
||||||
b.Workflow.Spec.ServiceAccountName = "sa-" + namespace
|
|
||||||
b.Workflow.Spec.Entrypoint = "dag"
|
b.Workflow.Spec.Entrypoint = "dag"
|
||||||
b.Workflow.ApiVersion = "argoproj.io/v1alpha1"
|
b.Workflow.ApiVersion = "argoproj.io/v1alpha1"
|
||||||
b.Workflow.Kind = "Workflow"
|
b.Workflow.Kind = "Workflow"
|
||||||
if !write {
|
if !write {
|
||||||
return len(b.Workflow.getDag().Tasks), firstItems, lastItems, nil
|
return "", len(b.Workflow.getDag().Tasks), firstItems, lastItems, nil
|
||||||
}
|
}
|
||||||
|
random_name := fakelish.GenerateFakeWord(5, 8) + "-" + fakelish.GenerateFakeWord(5, 8)
|
||||||
return len(b.Workflow.getDag().Tasks), firstItems, lastItems, nil
|
b.Workflow.Metadata.Name = "oc-monitor-" + random_name
|
||||||
|
logger = oclib.GetLogger()
|
||||||
|
yamlified, err := yaml.Marshal(b.Workflow)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error().Msg("Could not transform object to yaml file")
|
||||||
|
return "", 0, firstItems, lastItems, err
|
||||||
|
}
|
||||||
|
// Give a unique name to each argo file with its timestamp DD:MM:YYYY_hhmmss
|
||||||
|
current_timestamp := time.Now().Format("02_01_2006_150405")
|
||||||
|
file_name := random_name + "_" + current_timestamp + ".yml"
|
||||||
|
workflows_dir := "./argo_workflows/"
|
||||||
|
err = os.WriteFile(workflows_dir+file_name, []byte(yamlified), 0660)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error().Msg("Could not write the yaml file")
|
||||||
|
return "", 0, firstItems, lastItems, err
|
||||||
|
}
|
||||||
|
return workflows_dir + file_name, len(b.Workflow.getDag().Tasks), firstItems, lastItems, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createTemplates parcourt tous les nœuds du graphe (processings, native tools,
|
func (b *ArgoBuilder) createTemplates(namespace string) ([]string, []string, []VolumeMount) {
|
||||||
// sous-workflows) et génère les templates Argo correspondants.
|
|
||||||
// Elle gère également le recâblage des dépendances DAG entre sous-workflows
|
|
||||||
// imbriqués, et l'ajout du pod de service si nécessaire.
|
|
||||||
// Retourne les premières tâches, les dernières tâches et les volumes à créer.
|
|
||||||
func (b *ArgoBuilder) createTemplates(exec *workflow_execution.WorkflowExecution, namespace string) ([]string, []string, []VolumeMount) {
|
|
||||||
volumes := []VolumeMount{}
|
volumes := []VolumeMount{}
|
||||||
firstItems := []string{}
|
firstItems := []string{}
|
||||||
lastItems := []string{}
|
lastItems := []string{}
|
||||||
|
items := b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing)
|
||||||
// --- Processings ---
|
fmt.Println("Creating templates", len(items))
|
||||||
for _, item := range b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing) {
|
for _, item := range b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing) {
|
||||||
index := 0
|
instance := item.Processing.GetSelectedInstance()
|
||||||
_, res := item.GetResource()
|
fmt.Println("Creating template for", item.Processing.GetName(), instance)
|
||||||
if d, ok := exec.SelectedInstances[res.GetID()]; ok {
|
|
||||||
index = d
|
|
||||||
}
|
|
||||||
instance := item.Processing.GetSelectedInstance(&index)
|
|
||||||
logger.Info().Msg(fmt.Sprint("Creating template for", item.Processing.GetName(), instance))
|
|
||||||
if instance == nil || instance.(*resources.ProcessingInstance).Access == nil && instance.(*resources.ProcessingInstance).Access.Container != nil {
|
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())
|
logger.Error().Msg("Not enough configuration setup, template can't be created : " + item.Processing.GetName())
|
||||||
return firstItems, lastItems, volumes
|
return firstItems, lastItems, volumes
|
||||||
}
|
}
|
||||||
volumes, firstItems, lastItems = b.createArgoTemplates(exec,
|
volumes, firstItems, lastItems = b.createArgoTemplates(namespace,
|
||||||
namespace,
|
|
||||||
item.ID, item.Processing, volumes, firstItems, lastItems)
|
item.ID, item.Processing, volumes, firstItems, lastItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Native Tools de type WORKFLOW_EVENT uniquement ---
|
|
||||||
for _, item := range b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsNativeTool) {
|
|
||||||
if item.NativeTool.Kind != int(native_tools.WORKFLOW_EVENT) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
index := 0
|
|
||||||
_, res := item.GetResource()
|
|
||||||
if d, ok := exec.SelectedInstances[res.GetID()]; ok {
|
|
||||||
index = d
|
|
||||||
}
|
|
||||||
instance := item.NativeTool.GetSelectedInstance(&index)
|
|
||||||
logger.Info().Msg(fmt.Sprint("Creating template for", item.NativeTool.GetName(), instance))
|
|
||||||
volumes, firstItems, lastItems = b.createArgoTemplates(exec,
|
|
||||||
namespace, item.ID, item.NativeTool, volumes, firstItems, lastItems)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Sous-workflows : chargement, construction récursive et fusion du DAG ---
|
|
||||||
firstWfTasks := map[string][]string{}
|
firstWfTasks := map[string][]string{}
|
||||||
latestWfTasks := map[string][]string{}
|
latestWfTasks := map[string][]string{}
|
||||||
relatedWfTasks := map[string][]string{}
|
relatedWfTasks := map[string][]string{}
|
||||||
@@ -172,28 +123,24 @@ func (b *ArgoBuilder) createTemplates(exec *workflow_execution.WorkflowExecution
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
subBuilder := ArgoBuilder{OriginWorkflow: realWorkflow.(*w.Workflow), Timeout: b.Timeout}
|
subBuilder := ArgoBuilder{OriginWorkflow: realWorkflow.(*w.Workflow), Timeout: b.Timeout}
|
||||||
_, fi, li, err := subBuilder.CreateDAG(exec, namespace, false)
|
_, _, fi, li, err := subBuilder.CreateDAG(namespace, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Msg("Error creating the subworkflow : " + err.Error())
|
logger.Error().Msg("Error creating the subworkflow : " + err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
firstWfTasks[wf] = fi
|
firstWfTasks[wf] = fi
|
||||||
if ok, depsOfIds := subBuilder.isArgoDependancy(wf); ok { // le sous-workflow est une dépendance d'autre chose
|
if ok, depsOfIds := subBuilder.isArgoDependancy(wf); ok { // IS BEFORE
|
||||||
latestWfTasks[wf] = li
|
latestWfTasks[wf] = li
|
||||||
relatedWfTasks[wf] = depsOfIds
|
relatedWfTasks[wf] = depsOfIds
|
||||||
}
|
}
|
||||||
// Fusion des tâches, templates, volumes et arguments du sous-workflow dans le DAG principal.
|
|
||||||
subDag := subBuilder.Workflow.getDag()
|
subDag := subBuilder.Workflow.getDag()
|
||||||
d := b.Workflow.getDag()
|
d := b.Workflow.getDag()
|
||||||
d.Tasks = append(d.Tasks, subDag.Tasks...)
|
d.Tasks = append(d.Tasks, subDag.Tasks...) // add the tasks of the subworkflow to the main workflow
|
||||||
b.Workflow.Spec.Templates = append(b.Workflow.Spec.Templates, subBuilder.Workflow.Spec.Templates...)
|
b.Workflow.Spec.Templates = append(b.Workflow.Spec.Templates, subBuilder.Workflow.Spec.Templates...)
|
||||||
b.Workflow.Spec.Volumes = append(b.Workflow.Spec.Volumes, subBuilder.Workflow.Spec.Volumes...)
|
b.Workflow.Spec.Volumes = append(b.Workflow.Spec.Volumes, subBuilder.Workflow.Spec.Volumes...)
|
||||||
b.Workflow.Spec.Arguments = append(b.Workflow.Spec.Arguments, subBuilder.Workflow.Spec.Arguments...)
|
b.Workflow.Spec.Arguments = append(b.Workflow.Spec.Arguments, subBuilder.Workflow.Spec.Arguments...)
|
||||||
b.Services = append(b.Services, subBuilder.Services...)
|
b.Services = append(b.Services, subBuilder.Services...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recâblage : les tâches qui dépendaient du sous-workflow dépendent désormais
|
|
||||||
// de sa dernière tâche réelle (latestWfTasks).
|
|
||||||
for wfID, depsOfIds := range relatedWfTasks {
|
for wfID, depsOfIds := range relatedWfTasks {
|
||||||
for _, dep := range depsOfIds {
|
for _, dep := range depsOfIds {
|
||||||
for _, task := range b.Workflow.getDag().Tasks {
|
for _, task := range b.Workflow.getDag().Tasks {
|
||||||
@@ -213,9 +160,6 @@ func (b *ArgoBuilder) createTemplates(exec *workflow_execution.WorkflowExecution
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Les premières tâches du sous-workflow héritent des dépendances
|
|
||||||
// que le sous-workflow avait vis-à-vis du DAG principal.
|
|
||||||
for wfID, fi := range firstWfTasks {
|
for wfID, fi := range firstWfTasks {
|
||||||
deps := b.getArgoDependencies(wfID)
|
deps := b.getArgoDependencies(wfID)
|
||||||
if len(deps) > 0 {
|
if len(deps) > 0 {
|
||||||
@@ -228,8 +172,6 @@ func (b *ArgoBuilder) createTemplates(exec *workflow_execution.WorkflowExecution
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si des services Kubernetes sont nécessaires, on ajoute le pod dédié.
|
|
||||||
if b.Services != nil {
|
if b.Services != nil {
|
||||||
dag := b.Workflow.getDag()
|
dag := b.Workflow.getDag()
|
||||||
dag.Tasks = append(dag.Tasks, Task{Name: "workflow-service-pod", Template: "workflow-service-pod"})
|
dag.Tasks = append(dag.Tasks, Task{Name: "workflow-service-pod", Template: "workflow-service-pod"})
|
||||||
@@ -238,108 +180,102 @@ func (b *ArgoBuilder) createTemplates(exec *workflow_execution.WorkflowExecution
|
|||||||
return firstItems, lastItems, volumes
|
return firstItems, lastItems, volumes
|
||||||
}
|
}
|
||||||
|
|
||||||
// createArgoTemplates crée le template Argo pour un nœud du graphe (processing
|
func (b *ArgoBuilder) GetByRelatedProcessing(w *workflow.Workflow, processingID string, g func(item graph.GraphItem) bool) []string {
|
||||||
// ou native tool). Il :
|
related := []string{}
|
||||||
// 1. Ajoute la tâche au DAG avec ses dépendances.
|
for _, link := range w.Graph.Links {
|
||||||
// 2. Crée le template de container (ou d'événement pour les native tools).
|
nodeID := link.Destination.ID
|
||||||
// 3. Ajoute les annotations Admiralty si le processing est hébergé sur un peer distant.
|
var node resources.ResourceInterface
|
||||||
// 4. Crée un service Kubernetes si le processing est déclaré IsService.
|
if g(w.Graph.Items[link.Source.ID]) {
|
||||||
// 5. Configure les annotations de stockage (S3, volumes locaux).
|
item := w.Graph.Items[link.Source.ID]
|
||||||
func (b *ArgoBuilder) createArgoTemplates(
|
_, node = item.GetResource()
|
||||||
exec *workflow_execution.WorkflowExecution,
|
}
|
||||||
namespace string,
|
if node == nil && g(w.Graph.Items[link.Destination.ID]) { // if the source is not a storage, we consider that the destination is the storage
|
||||||
|
nodeID = link.Source.ID
|
||||||
|
item := w.Graph.Items[link.Destination.ID] // and the processing is the source
|
||||||
|
_, node = item.GetResource() // we are looking for the storage as destination
|
||||||
|
}
|
||||||
|
if processingID == nodeID && node != nil { // if the storage is linked to the processing
|
||||||
|
related = append(related, node.GetID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return related
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *ArgoBuilder) createArgoTemplates(namespace string,
|
||||||
id string,
|
id string,
|
||||||
obj resources.ResourceInterface,
|
processing *resources.ProcessingResource,
|
||||||
volumes []VolumeMount,
|
volumes []VolumeMount,
|
||||||
firstItems []string,
|
firstItems []string,
|
||||||
lastItems []string) ([]VolumeMount, []string, []string) {
|
lastItems []string) ([]VolumeMount, []string, []string) {
|
||||||
|
_, firstItems, lastItems = b.addTaskToArgo(b.Workflow.getDag(), id, processing, firstItems, lastItems)
|
||||||
_, firstItems, lastItems = b.addTaskToArgo(exec, b.Workflow.getDag(), id, obj, firstItems, lastItems)
|
template := &Template{Name: getArgoName(processing.GetName(), id)}
|
||||||
template := &Template{Name: getArgoName(obj.GetName(), id)}
|
fmt.Println("Creating template for", template.Name)
|
||||||
logger.Info().Msg(fmt.Sprint("Creating template for", template.Name))
|
template.CreateContainer(processing, b.Workflow.getDag(), template.Name)
|
||||||
// Vérifie si le processing est sur un peer distant (Admiralty).
|
// get datacenter from the processing
|
||||||
isReparted, peer := b.isReparted(obj, id)
|
if processing.IsService {
|
||||||
if obj.GetType() == tools.PROCESSING_RESOURCE.String() {
|
b.CreateService(id, processing)
|
||||||
template.CreateContainer(exec, obj.(*resources.ProcessingResource), b.Workflow.getDag())
|
|
||||||
} else if obj.GetType() == tools.NATIVE_TOOL.String() {
|
|
||||||
template.CreateEventContainer(exec, obj.(*resources.NativeTool), b.Workflow.getDag())
|
|
||||||
}
|
|
||||||
|
|
||||||
if isReparted {
|
|
||||||
logger.Debug().Msg("Reparted processing, on " + peer.GetID())
|
|
||||||
b.RemotePeers = append(b.RemotePeers, peer.GetID())
|
|
||||||
template.AddAdmiraltyAnnotations(peer.GetID())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si le processing expose un service Kubernetes, on l'enregistre et on
|
|
||||||
// applique le label "app" pour que le Service puisse le sélectionner.
|
|
||||||
if obj.GetType() == tools.PROCESSING_RESOURCE.String() && obj.(*resources.ProcessingResource).IsService {
|
|
||||||
b.CreateService(exec, id, obj)
|
|
||||||
template.Metadata.Labels = make(map[string]string)
|
template.Metadata.Labels = make(map[string]string)
|
||||||
template.Metadata.Labels["app"] = "oc-service-" + obj.GetName()
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
volumes = b.addStorageAnnotations(exec, id, template, namespace, volumes)
|
|
||||||
b.Workflow.Spec.Templates = append(b.Workflow.Spec.Templates, *template)
|
|
||||||
return volumes, firstItems, lastItems
|
|
||||||
}
|
|
||||||
|
|
||||||
// addStorageAnnotations parcourt tous les nœuds de stockage liés au processing
|
|
||||||
// identifié par id. Pour chaque lien de stockage :
|
|
||||||
// - Construit le nom de l'artefact Argo (lecture ou écriture).
|
|
||||||
// - Pour les stockages S3 : appelle waitForConsiders (STORAGE_RESOURCE) pour
|
|
||||||
// attendre la validation PB_CONSIDERS avant de configurer les annotations S3.
|
|
||||||
// - Pour les volumes locaux : ajoute un VolumeMount dans le container.
|
|
||||||
func (b *ArgoBuilder) addStorageAnnotations(exec *workflow_execution.WorkflowExecution, id string, template *Template, namespace string, volumes []VolumeMount) []VolumeMount {
|
|
||||||
// Récupère tous les nœuds de stockage connectés au processing courant.
|
|
||||||
related := b.OriginWorkflow.GetByRelatedProcessing(id, b.OriginWorkflow.Graph.IsStorage)
|
related := b.OriginWorkflow.GetByRelatedProcessing(id, b.OriginWorkflow.Graph.IsStorage)
|
||||||
|
|
||||||
for _, r := range related {
|
for _, r := range related {
|
||||||
storage := r.Node.(*resources.StorageResource)
|
storage := r.Node.(*resources.StorageResource)
|
||||||
for _, linkToStorage := range r.Links {
|
for _, linkToStorage := range r.Links {
|
||||||
for _, rw := range linkToStorage.StorageLinkInfos {
|
for _, rw := range linkToStorage.StorageLinkInfos {
|
||||||
var art Artifact
|
art := Artifact{Path: template.ReplacePerEnv(rw.Source, linkToStorage.Env)}
|
||||||
// Le nom de l'artefact doit être alphanumérique + '-' ou '_'.
|
|
||||||
artifactBaseName := strings.Join(strings.Split(storage.GetName(), " "), "-") + "-" + strings.Replace(rw.FileName, ".", "-", -1)
|
|
||||||
if rw.Write {
|
if rw.Write {
|
||||||
// Écriture vers S3 : Path = chemin du fichier dans le pod.
|
art.Name = storage.GetName() + "-" + rw.Destination + "-input-write"
|
||||||
art = Artifact{Path: template.ReplacePerEnv(rw.Source, linkToStorage.Env)}
|
|
||||||
art.Name = artifactBaseName + "-input-write"
|
|
||||||
} else {
|
} else {
|
||||||
// Lecture depuis S3 : Path = destination dans le pod.
|
art.Name = storage.GetName() + "-" + rw.Destination + "-input-read"
|
||||||
art = Artifact{Path: template.ReplacePerEnv(rw.Destination+"/"+rw.FileName, linkToStorage.Env)}
|
|
||||||
art.Name = artifactBaseName + "-input-read"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if storage.StorageType == enum.S3 {
|
if storage.StorageType == enum.S3 {
|
||||||
// Pour chaque ressource de compute liée à ce stockage S3,
|
art.S3 = &Key{
|
||||||
// on notifie via NATS et on attend la validation PB_CONSIDERS
|
Key: template.ReplacePerEnv(rw.Destination+"/"+rw.FileName, linkToStorage.Env),
|
||||||
// avec DataType = STORAGE_RESOURCE avant de continuer.
|
Insecure: true, // temporary
|
||||||
for _, r := range b.getStorageRelatedProcessing(storage.GetID()) {
|
}
|
||||||
waitForConsiders(exec.ExecutionsID, tools.STORAGE_RESOURCE, ArgoKubeEvent{
|
sel := storage.GetSelectedInstance()
|
||||||
ExecutionsID: exec.ExecutionsID,
|
if sel != nil {
|
||||||
DestPeerID: r.GetID(),
|
if sel.(*resources.StorageResourceInstance).Credentials != nil {
|
||||||
Type: tools.STORAGE_RESOURCE,
|
tool, err := tools2.NewService(conf.GetConfig().Mode)
|
||||||
SourcePeerID: storage.GetCreatorID(),
|
if err != nil || tool == nil {
|
||||||
OriginID: conf.GetConfig().PeerID,
|
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]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Configure la référence au dépôt d'artefacts S3 dans le Spec.
|
|
||||||
b.addS3annotations(storage, namespace)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if rw.Write {
|
if rw.Write {
|
||||||
template.Outputs.Artifacts = append(template.Outputs.Artifacts, art)
|
template.Outputs.Artifacts = append(template.Inputs.Artifacts, art)
|
||||||
} else {
|
} else {
|
||||||
template.Inputs.Artifacts = append(template.Inputs.Artifacts, art)
|
template.Inputs.Artifacts = append(template.Outputs.Artifacts, art)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si l'instance de stockage est locale, on monte un volume persistant.
|
|
||||||
index := 0
|
index := 0
|
||||||
if s, ok := exec.SelectedInstances[storage.GetID()]; ok {
|
if storage.SelectedInstanceIndex != nil && (*storage.SelectedInstanceIndex) >= 0 {
|
||||||
index = s
|
index = *storage.SelectedInstanceIndex
|
||||||
}
|
}
|
||||||
s := storage.Instances[index]
|
s := storage.Instances[index]
|
||||||
if s.Local {
|
if s.Local {
|
||||||
@@ -350,78 +286,15 @@ func (b *ArgoBuilder) addStorageAnnotations(exec *workflow_execution.WorkflowExe
|
|||||||
}, volumes)
|
}, volumes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return volumes
|
b.Workflow.Spec.Templates = append(b.Workflow.Spec.Templates, *template)
|
||||||
|
return volumes, firstItems, lastItems
|
||||||
}
|
}
|
||||||
|
func (b *ArgoBuilder) addTaskToArgo(dag *Dag, graphItemID string, processing *resources.ProcessingResource,
|
||||||
// getStorageRelatedProcessing retourne la liste des ressources de compute
|
|
||||||
// connectées (via un processing intermédiaire) au stockage identifié par storageId.
|
|
||||||
// Ces ressources sont utilisées pour construire les ArgoKubeEvent destinés
|
|
||||||
// à la validation NATS.
|
|
||||||
func (b *ArgoBuilder) getStorageRelatedProcessing(storageId string) (res []resources.ResourceInterface) {
|
|
||||||
var storageLinks []graph.GraphLink
|
|
||||||
// On ne conserve que les liens impliquant ce stockage.
|
|
||||||
for _, link := range b.OriginWorkflow.Graph.Links {
|
|
||||||
if link.Destination.ID == storageId || link.Source.ID == storageId {
|
|
||||||
storageLinks = append(storageLinks, link)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, link := range storageLinks {
|
|
||||||
var resourceId string
|
|
||||||
// L'opposé du lien est soit la source soit la destination selon la direction.
|
|
||||||
if link.Source.ID != storageId {
|
|
||||||
resourceId = link.Source.ID
|
|
||||||
} else {
|
|
||||||
resourceId = link.Destination.ID
|
|
||||||
}
|
|
||||||
// Si l'opposé est un processing, on récupère ses ressources de compute.
|
|
||||||
if b.OriginWorkflow.Graph.IsProcessing(b.OriginWorkflow.Graph.Items[resourceId]) {
|
|
||||||
res = append(res, b.getComputeProcessing(resourceId)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// getComputeProcessing retourne toutes les ressources de compute attachées
|
|
||||||
// au processing identifié par processingId dans le graphe du workflow.
|
|
||||||
func (b *ArgoBuilder) getComputeProcessing(processingId string) (res []resources.ResourceInterface) {
|
|
||||||
arr := []resources.ResourceInterface{}
|
|
||||||
computeRel := b.OriginWorkflow.GetByRelatedProcessing(processingId, b.OriginWorkflow.Graph.IsCompute)
|
|
||||||
for _, rel := range computeRel {
|
|
||||||
arr = append(arr, rel.Node)
|
|
||||||
}
|
|
||||||
return arr
|
|
||||||
}
|
|
||||||
|
|
||||||
// addS3annotations configure la référence au dépôt d'artefacts S3 dans le Spec
|
|
||||||
// du workflow Argo. La ConfigMap et la clé sont dérivées de l'ID du stockage.
|
|
||||||
// Le namespace est conservé en signature pour une évolution future.
|
|
||||||
func (b *ArgoBuilder) addS3annotations(storage *resources.StorageResource, namespace string) {
|
|
||||||
b.Workflow.Spec.ArtifactRepositoryRef = ArtifactRepositoryRef{
|
|
||||||
ConfigMap: storage.GetID() + "-artifact-repository",
|
|
||||||
Key: storage.GetID() + "-s3-local",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// addTaskToArgo ajoute une tâche au DAG Argo pour le nœud graphItemID.
|
|
||||||
// Elle résout les dépendances DAG, propage les paramètres d'environnement,
|
|
||||||
// d'entrée et de sortie de l'instance sélectionnée, et met à jour les listes
|
|
||||||
// firstItems / lastItems utilisées pour le recâblage des sous-workflows.
|
|
||||||
func (b *ArgoBuilder) addTaskToArgo(exec *workflow_execution.WorkflowExecution, dag *Dag, graphItemID string, processing resources.ResourceInterface,
|
|
||||||
firstItems []string, lastItems []string) (*Dag, []string, []string) {
|
firstItems []string, lastItems []string) (*Dag, []string, []string) {
|
||||||
|
|
||||||
unique_name := getArgoName(processing.GetName(), graphItemID)
|
unique_name := getArgoName(processing.GetName(), graphItemID)
|
||||||
step := Task{Name: unique_name, Template: unique_name}
|
step := Task{Name: unique_name, Template: unique_name}
|
||||||
|
instance := processing.GetSelectedInstance()
|
||||||
index := 0
|
|
||||||
if d, ok := exec.SelectedInstances[processing.GetID()]; ok {
|
|
||||||
index = d
|
|
||||||
}
|
|
||||||
instance := processing.GetSelectedInstance(&index)
|
|
||||||
if instance != nil {
|
if instance != nil {
|
||||||
// Propagation des variables d'environnement, entrées et sorties
|
|
||||||
// de l'instance vers les paramètres de la tâche Argo.
|
|
||||||
for _, value := range instance.(*resources.ProcessingInstance).Env {
|
for _, value := range instance.(*resources.ProcessingInstance).Env {
|
||||||
step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{
|
step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{
|
||||||
Name: value.Name,
|
Name: value.Name,
|
||||||
@@ -441,10 +314,7 @@ func (b *ArgoBuilder) addTaskToArgo(exec *workflow_execution.WorkflowExecution,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
step.Dependencies = b.getArgoDependencies(graphItemID)
|
step.Dependencies = b.getArgoDependencies(graphItemID)
|
||||||
|
|
||||||
// Détermine si ce nœud est une première ou une dernière tâche du DAG.
|
|
||||||
name := ""
|
name := ""
|
||||||
if b.OriginWorkflow.Graph.Items[graphItemID].Processing != nil {
|
if b.OriginWorkflow.Graph.Items[graphItemID].Processing != nil {
|
||||||
name = b.OriginWorkflow.Graph.Items[graphItemID].Processing.GetName()
|
name = b.OriginWorkflow.Graph.Items[graphItemID].Processing.GetName()
|
||||||
@@ -458,19 +328,15 @@ func (b *ArgoBuilder) addTaskToArgo(exec *workflow_execution.WorkflowExecution,
|
|||||||
if ok, _ := b.isArgoDependancy(graphItemID); !ok && name != "" {
|
if ok, _ := b.isArgoDependancy(graphItemID); !ok && name != "" {
|
||||||
lastItems = append(lastItems, getArgoName(name, graphItemID))
|
lastItems = append(lastItems, getArgoName(name, graphItemID))
|
||||||
}
|
}
|
||||||
|
|
||||||
dag.Tasks = append(dag.Tasks, step)
|
dag.Tasks = append(dag.Tasks, step)
|
||||||
return dag, firstItems, lastItems
|
return dag, firstItems, lastItems
|
||||||
}
|
}
|
||||||
|
|
||||||
// createVolumes crée les PersistentVolumeClaims Argo (volumeClaimTemplates)
|
func (b *ArgoBuilder) createVolumes(volumes []VolumeMount) { // TODO : one think about remote volume but TG
|
||||||
// pour chaque volume local référencé dans les templates de processing.
|
|
||||||
// TODO: gérer les volumes distants.
|
|
||||||
func (b *ArgoBuilder) createVolumes(exec *workflow_execution.WorkflowExecution, volumes []VolumeMount) {
|
|
||||||
for _, volume := range volumes {
|
for _, volume := range volumes {
|
||||||
index := 0
|
index := 0
|
||||||
if s, ok := exec.SelectedInstances[volume.Storage.GetID()]; ok {
|
if volume.Storage.SelectedInstanceIndex != nil && (*volume.Storage.SelectedInstanceIndex) >= 0 {
|
||||||
index = s
|
index = *volume.Storage.SelectedInstanceIndex
|
||||||
}
|
}
|
||||||
storage := volume.Storage.Instances[index]
|
storage := volume.Storage.Instances[index]
|
||||||
new_volume := VolumeClaimTemplate{}
|
new_volume := VolumeClaimTemplate{}
|
||||||
@@ -481,16 +347,12 @@ func (b *ArgoBuilder) createVolumes(exec *workflow_execution.WorkflowExecution,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isArgoDependancy vérifie si le nœud identifié par id est une dépendance
|
|
||||||
// d'au moins un autre nœud du DAG (i.e. s'il existe un lien sortant vers
|
|
||||||
// un processing ou un workflow).
|
|
||||||
// Retourne true + la liste des noms Argo des nœuds qui en dépendent.
|
|
||||||
func (b *ArgoBuilder) isArgoDependancy(id string) (bool, []string) {
|
func (b *ArgoBuilder) isArgoDependancy(id string) (bool, []string) {
|
||||||
dependancyOfIDs := []string{}
|
dependancyOfIDs := []string{}
|
||||||
isDeps := false
|
isDeps := false
|
||||||
for _, link := range b.OriginWorkflow.Graph.Links {
|
for _, link := range b.OriginWorkflow.Graph.Links {
|
||||||
if _, ok := b.OriginWorkflow.Graph.Items[link.Destination.ID]; !ok {
|
if _, ok := b.OriginWorkflow.Graph.Items[link.Destination.ID]; !ok {
|
||||||
logger.Info().Msg(fmt.Sprint("Could not find the source of the link", link.Destination.ID))
|
fmt.Println("Could not find the source of the link", link.Destination.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
source := b.OriginWorkflow.Graph.Items[link.Destination.ID].Processing
|
source := b.OriginWorkflow.Graph.Items[link.Destination.ID].Processing
|
||||||
@@ -507,12 +369,10 @@ func (b *ArgoBuilder) isArgoDependancy(id string) (bool, []string) {
|
|||||||
return isDeps, dependancyOfIDs
|
return isDeps, dependancyOfIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
// getArgoDependencies retourne la liste des noms de tâches Argo dont dépend
|
|
||||||
// le nœud identifié par id (liens entrants depuis des processings).
|
|
||||||
func (b *ArgoBuilder) getArgoDependencies(id string) (dependencies []string) {
|
func (b *ArgoBuilder) getArgoDependencies(id string) (dependencies []string) {
|
||||||
for _, link := range b.OriginWorkflow.Graph.Links {
|
for _, link := range b.OriginWorkflow.Graph.Links {
|
||||||
if _, ok := b.OriginWorkflow.Graph.Items[link.Source.ID]; !ok {
|
if _, ok := b.OriginWorkflow.Graph.Items[link.Source.ID]; !ok {
|
||||||
logger.Info().Msg(fmt.Sprint("Could not find the source of the link", link.Source.ID))
|
fmt.Println("Could not find the source of the link", link.Source.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
source := b.OriginWorkflow.Graph.Items[link.Source.ID].Processing
|
source := b.OriginWorkflow.Graph.Items[link.Source.ID].Processing
|
||||||
@@ -525,223 +385,9 @@ func (b *ArgoBuilder) getArgoDependencies(id string) (dependencies []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// getArgoName construit le nom unique d'une tâche / template Argo à partir
|
|
||||||
// du nom humain de la ressource et de son ID dans le graphe.
|
|
||||||
// Les espaces sont remplacés par des tirets et tout est mis en minuscules.
|
|
||||||
func getArgoName(raw_name string, component_id string) (formatedName string) {
|
func getArgoName(raw_name string, component_id string) (formatedName string) {
|
||||||
formatedName = strings.ReplaceAll(raw_name, " ", "-")
|
formatedName = strings.ReplaceAll(raw_name, " ", "-")
|
||||||
formatedName += "-" + component_id
|
formatedName += "-" + component_id
|
||||||
formatedName = strings.ToLower(formatedName)
|
formatedName = strings.ToLower(formatedName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// isReparted vérifie si le processing est hébergé sur un Compute appartenant
|
|
||||||
// à un peer distant (Relation != 1, i.e. pas le peer local).
|
|
||||||
// Si c'est le cas, elle retourne true et le Peer concerné pour qu'Admiralty
|
|
||||||
// puisse router les pods vers le bon cluster.
|
|
||||||
func (b *ArgoBuilder) isReparted(processing resources.ResourceInterface, graphID string) (bool, *peer.Peer) {
|
|
||||||
computeAttached := b.retrieveProcessingCompute(graphID)
|
|
||||||
if computeAttached == nil {
|
|
||||||
logger.Error().Msg("No compute was found attached to processing " + processing.GetName() + " : " + processing.GetID())
|
|
||||||
panic(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Résolution du Peer propriétaire du Compute via l'API oc-lib.
|
|
||||||
req := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", nil, nil)
|
|
||||||
if req == nil {
|
|
||||||
fmt.Println("TODO : handle error when trying to create a request on the Peer Collection")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
res := req.LoadOne(computeAttached.CreatorID)
|
|
||||||
if res.Err != "" {
|
|
||||||
fmt.Print("TODO : handle error when requesting PeerID")
|
|
||||||
fmt.Print(res.Err)
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := res.ToPeer()
|
|
||||||
|
|
||||||
// Relation == 1 signifie "moi-même" : le processing est local.
|
|
||||||
isNotReparted := peer.Relation == 1
|
|
||||||
logger.Info().Msg(fmt.Sprint("Result IsMySelf for ", peer.UUID, " : ", isNotReparted))
|
|
||||||
|
|
||||||
return !isNotReparted, peer
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieveProcessingCompute parcourt les liens du graphe pour retrouver
|
|
||||||
// la ressource de Compute directement connectée au nœud graphID.
|
|
||||||
// Retourne nil si aucun Compute n'est trouvé.
|
|
||||||
func (b *ArgoBuilder) retrieveProcessingCompute(graphID string) *resources.ComputeResource {
|
|
||||||
for _, link := range b.OriginWorkflow.Graph.Links {
|
|
||||||
var oppositeId string
|
|
||||||
if link.Source.ID == graphID {
|
|
||||||
oppositeId = link.Destination.ID
|
|
||||||
} else if link.Destination.ID == graphID {
|
|
||||||
oppositeId = link.Source.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
if oppositeId != "" {
|
|
||||||
dt, res := b.OriginWorkflow.Graph.GetResource(oppositeId)
|
|
||||||
if dt == oclib.COMPUTE_RESOURCE {
|
|
||||||
return res.(*resources.ComputeResource)
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForConsiders publie un ArgoKubeEvent sur le canal NATS ARGO_KUBE_EVENT
|
|
||||||
// puis se bloque jusqu'à réception d'un PropalgationMessage vérifiant :
|
|
||||||
// - Action == PB_CONSIDERS
|
|
||||||
// - DataType == dataType (COMPUTE_RESOURCE ou STORAGE_RESOURCE)
|
|
||||||
// - Payload décodé en JSON contenant "executions_id" == executionsId
|
|
||||||
//
|
|
||||||
// Cela garantit que l'infrastructure distante (Admiralty ou Minio) a bien
|
|
||||||
// pris en compte la demande avant que la construction du workflow continue.
|
|
||||||
// Un timeout de 5 minutes est appliqué pour éviter un blocage indéfini.
|
|
||||||
func waitForConsiders(executionsId string, dataType tools.DataType, event ArgoKubeEvent) {
|
|
||||||
// Sérialise l'événement et le publie sur ARGO_KUBE_EVENT.
|
|
||||||
b, err := json.Marshal(event)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("Cannot marshal ArgoKubeEvent: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tools.NewNATSCaller().SetNATSPub(tools.ARGO_KUBE_EVENT, tools.NATSResponse{
|
|
||||||
FromApp: "oc-monitord",
|
|
||||||
Datatype: dataType,
|
|
||||||
User: "root",
|
|
||||||
Method: int(tools.PROPALGATION_EVENT),
|
|
||||||
Payload: b,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Connexion NATS pour écouter la réponse PB_CONSIDERS.
|
|
||||||
natsURL := oclib_config.GetConfig().NATSUrl
|
|
||||||
if natsURL == "" {
|
|
||||||
logger.Error().Msg("NATS_SERVER not set, skipping PB_CONSIDERS wait")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nc, err := nats.Connect(natsURL)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("NATS connect error waiting for PB_CONSIDERS: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer nc.Close()
|
|
||||||
|
|
||||||
// Souscription au canal PROPALGATION_EVENT avec un buffer de 64 messages.
|
|
||||||
ch := make(chan *nats.Msg, 64)
|
|
||||||
sub, err := nc.ChanSubscribe(tools.PROPALGATION_EVENT.GenerateKey(), ch)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("NATS subscribe error waiting for PB_CONSIDERS: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer sub.Unsubscribe()
|
|
||||||
|
|
||||||
timeout := time.After(5 * time.Minute)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case msg := <-ch:
|
|
||||||
// Désérialise le message en PropalgationMessage.
|
|
||||||
var pm tools.PropalgationMessage
|
|
||||||
if err := json.Unmarshal(msg.Data, &pm); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Filtre : action, type de données.
|
|
||||||
if pm.Action != tools.PB_CONSIDERS || pm.DataType != int(dataType) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Filtre : executions_id dans le Payload du PropalgationMessage.
|
|
||||||
var body struct {
|
|
||||||
ExecutionsID string `json:"executions_id"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(pm.Payload, &body); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if body.ExecutionsID != executionsId {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logger.Info().Msg(fmt.Sprintf("PB_CONSIDERS received for executions_id=%s datatype=%s", executionsId, dataType.String()))
|
|
||||||
return
|
|
||||||
case <-timeout:
|
|
||||||
logger.Warn().Msg(fmt.Sprintf("Timeout waiting for PB_CONSIDERS executions_id=%s datatype=%s", executionsId, dataType.String()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArgoKubeEvent est la structure publiée sur NATS lors de la demande de
|
|
||||||
// provisionnement d'une ressource distante (Admiralty ou stockage S3).
|
|
||||||
// Le champ OriginID identifie le peer initiateur : c'est vers lui que la
|
|
||||||
// réponse PB_CONSIDERS sera routée par le système de propagation.
|
|
||||||
type ArgoKubeEvent struct {
|
|
||||||
// ExecutionsID est l'identifiant de l'exécution de workflow en cours.
|
|
||||||
ExecutionsID string `json:"executions_id"`
|
|
||||||
// DestPeerID est le peer de destination (compute ou peer S3 cible).
|
|
||||||
DestPeerID string `json:"dest_peer_id"`
|
|
||||||
// Type indique la nature de la ressource : COMPUTE_RESOURCE ou STORAGE_RESOURCE.
|
|
||||||
Type tools.DataType `json:"data_type"`
|
|
||||||
// SourcePeerID est le peer source de la ressource demandée.
|
|
||||||
SourcePeerID string `json:"source_peer_id"`
|
|
||||||
// OriginID est le peer qui a initié la demande de provisionnement ;
|
|
||||||
// la réponse PB_CONSIDERS lui sera renvoyée.
|
|
||||||
OriginID string `json:"origin_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompleteBuild finalise la construction du workflow Argo après la génération
|
|
||||||
// du DAG. Elle effectue dans l'ordre :
|
|
||||||
// 1. Pour chaque peer distant (Admiralty) : publie un ArgoKubeEvent de type
|
|
||||||
// COMPUTE_RESOURCE et attend la validation PB_CONSIDERS via waitForConsiders.
|
|
||||||
// 2. Met à jour les annotations Admiralty des templates avec le nom de cluster
|
|
||||||
// construit à partir du peerId et de l'executionsId.
|
|
||||||
// 3. Sérialise le workflow en YAML et l'écrit dans ./argo_workflows/.
|
|
||||||
//
|
|
||||||
// Retourne le chemin du fichier YAML généré.
|
|
||||||
func (b *ArgoBuilder) CompleteBuild(executionsId string) (string, error) {
|
|
||||||
logger.Info().Msg("DEV :: Completing build")
|
|
||||||
|
|
||||||
// --- Étape 1 : validation Admiralty pour chaque peer distant ---
|
|
||||||
for _, peer := range b.RemotePeers {
|
|
||||||
logger.Info().Msg(fmt.Sprint("DEV :: Launching Admiralty Setup for ", peer))
|
|
||||||
// Publie l'événement COMPUTE_RESOURCE et attend PB_CONSIDERS (bloquant).
|
|
||||||
waitForConsiders(executionsId, tools.COMPUTE_RESOURCE, ArgoKubeEvent{
|
|
||||||
ExecutionsID: executionsId,
|
|
||||||
Type: tools.COMPUTE_RESOURCE,
|
|
||||||
DestPeerID: conf.GetConfig().PeerID,
|
|
||||||
SourcePeerID: peer,
|
|
||||||
OriginID: conf.GetConfig().PeerID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Étape 2 : mise à jour du nom de cluster Admiralty ---
|
|
||||||
// Le nom final du cluster cible est "target-<peerId>-<executionsId>".
|
|
||||||
for _, template := range b.Workflow.Spec.Templates {
|
|
||||||
if len(template.Metadata.Annotations) > 0 {
|
|
||||||
if peerId, ok := template.Metadata.Annotations["multicluster.admiralty.io/clustername"]; ok {
|
|
||||||
template.Metadata.Annotations["multicluster.admiralty.io/clustername"] = "target-" + tools.GetConcatenatedName(peerId, executionsId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Étape 3 : génération et écriture du fichier YAML ---
|
|
||||||
random_name := fakelish.GenerateFakeWord(5, 8) + "-" + fakelish.GenerateFakeWord(5, 8)
|
|
||||||
b.Workflow.Metadata.Name = "oc-monitor-" + random_name
|
|
||||||
logger = oclib.GetLogger()
|
|
||||||
yamlified, err := yaml.Marshal(b.Workflow)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("Could not transform object to yaml file")
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// Nom de fichier horodaté au format DD_MM_YYYY_hhmmss.
|
|
||||||
current_timestamp := time.Now().Format("02_01_2006_150405")
|
|
||||||
file_name := random_name + "_" + current_timestamp + ".yml"
|
|
||||||
workflows_dir := "./argo_workflows/"
|
|
||||||
err = os.WriteFile(workflows_dir+file_name, []byte(yamlified), 0660)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error().Msg("Could not write the yaml file")
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return workflows_dir + file_name, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
# argo_builder.go — Résumé
|
|
||||||
|
|
||||||
## Rôle général
|
|
||||||
|
|
||||||
`argo_builder.go` traduit un **Workflow Open Cloud** (graphe de nœuds : processings,
|
|
||||||
stockages, computes, sous-workflows) en un **fichier YAML Argo Workflow** prêt à
|
|
||||||
être soumis à un cluster Kubernetes.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Structures principales
|
|
||||||
|
|
||||||
| Struct | Rôle |
|
|
||||||
|---|---|
|
|
||||||
| `ArgoBuilder` | Constructeur principal. Porte le workflow source, la structure YAML en cours de build, les services k8s, le timeout et la liste des peers distants (Admiralty). |
|
|
||||||
| `Workflow` | Racine du YAML Argo (`apiVersion`, `kind`, `metadata`, `spec`). |
|
|
||||||
| `Spec` | Spécification du workflow : compte de service, entrypoint, templates, volumes, timeout, référence au dépôt d'artefacts S3. |
|
|
||||||
| `ArgoKubeEvent` | Événement publié sur NATS lors de la demande de provisionnement d'une ressource distante (compute ou stockage S3). Contient `executions_id`, `dest_peer_id`, `source_peer_id`, `data_type`, `origin_id`. |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Flux d'exécution principal
|
|
||||||
|
|
||||||
```
|
|
||||||
CreateDAG()
|
|
||||||
└─ createTemplates()
|
|
||||||
├─ [pour chaque processing] createArgoTemplates()
|
|
||||||
│ ├─ addTaskToArgo() → ajoute la tâche au DAG + dépendances
|
|
||||||
│ ├─ CreateContainer() → template container Argo
|
|
||||||
│ ├─ AddAdmiraltyAnnotations() → si peer distant détecté
|
|
||||||
│ └─ addStorageAnnotations() → S3 + volumes locaux
|
|
||||||
├─ [pour chaque native tool WORKFLOW_EVENT] createArgoTemplates()
|
|
||||||
└─ [pour chaque sous-workflow]
|
|
||||||
├─ CreateDAG() récursif
|
|
||||||
└─ fusion DAG + recâblage des dépendances
|
|
||||||
└─ createVolumes() → PersistentVolumeClaims
|
|
||||||
|
|
||||||
CompleteBuild()
|
|
||||||
├─ waitForConsiders() × N peers → validation Admiralty (COMPUTE_RESOURCE)
|
|
||||||
├─ mise à jour annotations Admiralty (clustername)
|
|
||||||
└─ écriture du YAML dans ./argo_workflows/
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fonctions clés
|
|
||||||
|
|
||||||
### `CreateDAG(exec, namespace, write) → (nbTâches, firstItems, lastItems, err)`
|
|
||||||
Point d'entrée. Initialise le logger, déclenche la création des templates et des
|
|
||||||
volumes, configure les métadonnées globales du workflow Argo.
|
|
||||||
|
|
||||||
### `createTemplates(exec, namespace) → (firstItems, lastItems, volumes)`
|
|
||||||
Itère sur tous les nœuds du graphe.
|
|
||||||
- Processings → template container.
|
|
||||||
- Native tools `WORKFLOW_EVENT` → template événement.
|
|
||||||
- Sous-workflows → build récursif + fusion DAG + recâblage des dépendances entrantes/sortantes.
|
|
||||||
|
|
||||||
### `createArgoTemplates(exec, namespace, id, obj, …)`
|
|
||||||
Crée le template Argo pour un nœud donné.
|
|
||||||
Détecte si le processing est **réparti** (peer distant via `isReparted`) → ajoute les
|
|
||||||
annotations Admiralty et enregistre le peer dans `RemotePeers`.
|
|
||||||
Délègue la configuration du stockage à `addStorageAnnotations`.
|
|
||||||
|
|
||||||
### `addStorageAnnotations(exec, id, template, namespace, volumes)`
|
|
||||||
Pour chaque stockage lié au processing :
|
|
||||||
- **S3** : appelle `waitForConsiders(STORAGE_RESOURCE)` pour chaque compute associé,
|
|
||||||
puis configure la référence au dépôt d'artefacts via `addS3annotations`.
|
|
||||||
- **Local** : monte un `VolumeMount` dans le container.
|
|
||||||
|
|
||||||
### `waitForConsiders(executionsId, dataType, event)`
|
|
||||||
**Fonction bloquante.**
|
|
||||||
1. Publie l'`ArgoKubeEvent` sur le canal NATS `ARGO_KUBE_EVENT`.
|
|
||||||
2. S'abonne à `PROPALGATION_EVENT`.
|
|
||||||
3. Attend un `PropalgationMessage` vérifiant :
|
|
||||||
- `Action == PB_CONSIDERS`
|
|
||||||
- `DataType == dataType`
|
|
||||||
- `Payload.executions_id == executionsId`
|
|
||||||
4. Timeout : **5 minutes**.
|
|
||||||
|
|
||||||
| Appelant | DataType attendu | Signification |
|
|
||||||
|---|---|---|
|
|
||||||
| `addStorageAnnotations` (S3) | `STORAGE_RESOURCE` | Le stockage S3 distant est prêt |
|
|
||||||
| `CompleteBuild` (Admiralty) | `COMPUTE_RESOURCE` | Le cluster cible Admiralty est configuré |
|
|
||||||
|
|
||||||
### `CompleteBuild(executionsId) → (cheminYAML, err)`
|
|
||||||
Finalise le build :
|
|
||||||
1. Pour chaque peer dans `RemotePeers` → `waitForConsiders(COMPUTE_RESOURCE)` (bloquant, séquentiel).
|
|
||||||
2. Met à jour les annotations `multicluster.admiralty.io/clustername` avec `target-<peerId>-<executionsId>`.
|
|
||||||
3. Sérialise le workflow en YAML et l'écrit dans `./argo_workflows/<nom>_<timestamp>.yml`.
|
|
||||||
|
|
||||||
### `isReparted(processing, graphID) → (bool, *peer.Peer)`
|
|
||||||
Retrouve le Compute attaché au processing, charge le Peer propriétaire via l'API
|
|
||||||
oc-lib, et vérifie si `Relation != 1` (pas le peer local).
|
|
||||||
|
|
||||||
### `addTaskToArgo(exec, dag, graphItemID, processing, …)`
|
|
||||||
Crée une `Task` Argo (nom unique, template, dépendances DAG, paramètres env/inputs/outputs)
|
|
||||||
et la rattache au DAG. Met à jour `firstItems` / `lastItems`.
|
|
||||||
|
|
||||||
### `isArgoDependancy(id) → (bool, []string)`
|
|
||||||
Vérifie si un nœud est utilisé comme source d'un lien sortant vers un autre
|
|
||||||
processing ou workflow (il est donc une dépendance pour quelqu'un).
|
|
||||||
|
|
||||||
### `getArgoDependencies(id) → []string`
|
|
||||||
Retourne les noms des tâches Argo dont ce nœud dépend (liens entrants).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Protocole NATS utilisé
|
|
||||||
|
|
||||||
```
|
|
||||||
Publication → canal : ARGO_KUBE_EVENT
|
|
||||||
payload : NATSResponse{Method: PROPALGATION_EVENT, Payload: ArgoKubeEvent}
|
|
||||||
|
|
||||||
Attente ← canal : PROPALGATION_EVENT
|
|
||||||
filtre : PropalgationMessage{
|
|
||||||
Action = PB_CONSIDERS,
|
|
||||||
DataType = COMPUTE_RESOURCE | STORAGE_RESOURCE,
|
|
||||||
Payload = {"executions_id": "<id en cours>"}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fichier YAML produit
|
|
||||||
|
|
||||||
- Nom : `oc-monitor-<mot1>-<mot2>_<DD_MM_YYYY_hhmmss>.yml`
|
|
||||||
- Dossier : `./argo_workflows/`
|
|
||||||
- Permissions : `0660`
|
|
||||||
@@ -5,11 +5,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/resources"
|
"cloud.o-forge.io/core/oc-lib/models/resources"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *ArgoBuilder) CreateService(exec *workflow_execution.WorkflowExecution, id string, processing resources.ResourceInterface) {
|
func (b *ArgoBuilder) CreateService(id string, processing *resources.ProcessingResource) {
|
||||||
new_service := models.Service{
|
new_service := models.Service{
|
||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
Kind: "Service",
|
Kind: "Service",
|
||||||
@@ -25,21 +24,17 @@ func (b *ArgoBuilder) CreateService(exec *workflow_execution.WorkflowExecution,
|
|||||||
if processing == nil {
|
if processing == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.completeServicePorts(exec, &new_service, id, processing)
|
b.completeServicePorts(&new_service, id, processing)
|
||||||
b.Services = append(b.Services, &new_service)
|
b.Services = append(b.Services, &new_service)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ArgoBuilder) completeServicePorts(exec *workflow_execution.WorkflowExecution, service *models.Service, id string, processing resources.ResourceInterface) {
|
func (b *ArgoBuilder) completeServicePorts(service *models.Service, id string, processing *resources.ProcessingResource) {
|
||||||
index := 0
|
instance := processing.GetSelectedInstance()
|
||||||
if d, ok := exec.SelectedInstances[processing.GetID()]; ok {
|
|
||||||
index = d
|
|
||||||
}
|
|
||||||
instance := processing.GetSelectedInstance(&index)
|
|
||||||
if instance != nil && instance.(*resources.ProcessingInstance).Access != nil && instance.(*resources.ProcessingInstance).Access.Container != nil {
|
if instance != nil && instance.(*resources.ProcessingInstance).Access != nil && instance.(*resources.ProcessingInstance).Access.Container != nil {
|
||||||
for _, execute := range instance.(*resources.ProcessingInstance).Access.Container.Exposes {
|
for _, execute := range instance.(*resources.ProcessingInstance).Access.Container.Exposes {
|
||||||
if execute.PAT != 0 {
|
if execute.PAT != 0 {
|
||||||
new_port_translation := models.ServicePort{
|
new_port_translation := models.ServicePort{
|
||||||
Name: strings.ToLower(processing.GetName()) + id,
|
Name: strings.ToLower(processing.Name) + id,
|
||||||
Port: execute.Port,
|
Port: execute.Port,
|
||||||
TargetPort: execute.PAT,
|
TargetPort: execute.PAT,
|
||||||
Protocol: "TCP",
|
Protocol: "TCP",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
workflow "cloud.o-forge.io/core/oc-lib/models/workflow"
|
workflow "cloud.o-forge.io/core/oc-lib/models/workflow"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorflowDB struct {
|
type WorflowDB struct {
|
||||||
@@ -15,7 +14,7 @@ type WorflowDB struct {
|
|||||||
|
|
||||||
// Create the obj!ects from the mxgraphxml stored in the workflow given as a parameter
|
// Create the obj!ects from the mxgraphxml stored in the workflow given as a parameter
|
||||||
func (w *WorflowDB) LoadFrom(workflow_id string, peerID string) error {
|
func (w *WorflowDB) LoadFrom(workflow_id string, peerID string) error {
|
||||||
logger.Info().Msg("Loading workflow from " + workflow_id)
|
fmt.Println("Loading workflow from " + workflow_id)
|
||||||
var err error
|
var err error
|
||||||
if w.Workflow, err = w.getWorkflow(workflow_id, peerID); err != nil {
|
if w.Workflow, err = w.getWorkflow(workflow_id, peerID); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -28,7 +27,7 @@ func (w *WorflowDB) getWorkflow(workflow_id string, peerID string) (workflow *wo
|
|||||||
logger := oclib.GetLogger()
|
logger := oclib.GetLogger()
|
||||||
|
|
||||||
lib_data := oclib.NewRequest(oclib.LibDataEnum(oclib.WORKFLOW), "", peerID, []string{}, nil).LoadOne(workflow_id)
|
lib_data := oclib.NewRequest(oclib.LibDataEnum(oclib.WORKFLOW), "", peerID, []string{}, nil).LoadOne(workflow_id)
|
||||||
logger.Info().Msg(fmt.Sprint("ERR", lib_data.Code, lib_data.Err))
|
fmt.Println("ERR", lib_data.Code, lib_data.Err)
|
||||||
if lib_data.Code != 200 {
|
if lib_data.Code != 200 {
|
||||||
logger.Error().Msg("Error loading the graph")
|
logger.Error().Msg("Error loading the graph")
|
||||||
return workflow, errors.New(lib_data.Err)
|
return workflow, errors.New(lib_data.Err)
|
||||||
@@ -42,20 +41,20 @@ func (w *WorflowDB) getWorkflow(workflow_id string, peerID string) (workflow *wo
|
|||||||
return new_wf, nil
|
return new_wf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorflowDB) ExportToArgo(exec *workflow_execution.WorkflowExecution, timeout int) (*ArgoBuilder, int, error) {
|
func (w *WorflowDB) ExportToArgo(namespace string, timeout int) (string, int, error) {
|
||||||
logger := oclib.GetLogger()
|
logger := oclib.GetLogger()
|
||||||
logger.Info().Msg(fmt.Sprint("Exporting to Argo", w.Workflow))
|
fmt.Println("Exporting to Argo", w.Workflow)
|
||||||
if len(w.Workflow.Name) == 0 || w.Workflow.Graph == nil {
|
if len(w.Workflow.Name) == 0 || w.Workflow.Graph == nil {
|
||||||
return nil, 0, fmt.Errorf("can't export a graph that has not been loaded yet")
|
return "", 0, fmt.Errorf("can't export a graph that has not been loaded yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
argoBuilder := ArgoBuilder{OriginWorkflow: w.Workflow, Timeout: timeout}
|
argo_builder := ArgoBuilder{OriginWorkflow: w.Workflow, Timeout: timeout}
|
||||||
stepMax, _, _, err := argoBuilder.CreateDAG(exec, exec.ExecutionsID, true)
|
filename, stepMax, _, _, err := argo_builder.CreateDAG(namespace, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Msg("Could not create the argo file for " + w.Workflow.Name)
|
logger.Error().Msg("Could not create the argo file for " + w.Workflow.Name)
|
||||||
return nil, 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
return &argoBuilder, stepMax, nil
|
return filename, stepMax, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO implement this function
|
// TODO implement this function
|
||||||
|
|||||||
Reference in New Issue
Block a user