Compare commits
92 Commits
fd8e397e16
...
feature/mi
| Author | SHA1 | Date | |
|---|---|---|---|
| d5e8db60be | |||
| a664423842 | |||
| 625f34ed21 | |||
|
|
55b88077d4 | ||
| 1d363e8f2a | |||
| 27c27fef15 | |||
| 8899673347 | |||
| 55da778ae1 | |||
| b06050bfae | |||
| 243db11a63 | |||
| 4e1e3f20af | |||
| 81167f7b86 | |||
| cb23289097 | |||
| c0b8ac1eee | |||
| f61c9f5df9 | |||
| c7290b0ead | |||
| 001539fb36 | |||
|
|
b372c10ab0 | ||
|
|
fd6186c6df | ||
|
|
5069b3455a | ||
|
|
cb2e4f6028 | ||
|
|
35facf1b74 | ||
|
|
24e0137444 | ||
|
|
ba940bfc80 | ||
|
|
063d57d9e7 | ||
|
|
484c742c31 | ||
|
|
cc3b2a6cfc | ||
|
|
8e8d0d3e01 | ||
|
|
03f81c66f9 | ||
|
|
be721059e5 | ||
| e4f0f6f4ca | |||
| cf92b46ce6 | |||
| aa42f5f49c | |||
|
|
98c54eb080 | ||
| afe442d17f | |||
|
|
46b7713404 | ||
| d5ad32e2e4 | |||
|
|
e4ecb8c1db | ||
| cca59faeab | |||
| 2cf8923d95 | |||
| 47ed1b4562 | |||
| 063f47c87b | |||
| bb03307b9e | |||
| 4bfb16cba6 | |||
| 3ae9f69525 | |||
| b08e6a1e70 | |||
| 1aa6c68b2c | |||
| 9d865f193d | |||
| 88e6c89612 | |||
| 2dca4aac62 | |||
| 7b43fa19ff | |||
| 150d6591be | |||
| 5a0489048a | |||
| 3c692d2026 | |||
| 0a15357445 | |||
| 4f2a713516 | |||
| 3bbb15c459 | |||
| b35f1c5ff3 | |||
| 7eac712e01 | |||
| 0baee5e339 | |||
| f69e9bf2fa | |||
| 293b52da4c | |||
| be7dc4f639 | |||
| 699e5b910c | |||
| 7f4c193b0f | |||
| 1896236cab | |||
| 429b034cb0 | |||
| 9e7b81061a | |||
| fadbc4f503 | |||
| 7147531e9d | |||
| fa97228e2b | |||
| 693571ddd7 | |||
| ba3afc69be | |||
| f75499d827 | |||
| 7b27945493 | |||
| 1d45b470b7 | |||
| 74ac2b6d9c | |||
| 44abc073c4 | |||
| f60474681b | |||
| 026e46450b | |||
| d26f0d6b1b | |||
| 3c313171c3 | |||
| 331c0835f1 | |||
| 198c1e1a28 | |||
| f7dd297b14 | |||
| 2d3224704a | |||
| 8eeae90b67 | |||
| 709e0300f9 | |||
| bff909abbb | |||
| a53dbccc23 | |||
| 43579a479f | |||
| ea69be8df1 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1 @@
|
||||
oc-datacenter
|
||||
swagger/
|
||||
@@ -1,3 +1,5 @@
|
||||
ARG KUBERNETES_HOST=${KUBERNETES_HOST:-"127.0.0.1"}
|
||||
|
||||
FROM golang:alpine AS deps
|
||||
|
||||
WORKDIR /app
|
||||
@@ -28,6 +30,9 @@ RUN export CGO_ENABLED=0 && \
|
||||
COPY . .
|
||||
|
||||
RUN sed -i '/replace/d' go.mod
|
||||
RUN if [ ! -f swagger/index.html ]; then timeout 15 bee run -gendoc=true -downdoc=true; fi
|
||||
RUN bee generate routers
|
||||
RUN bee generate docs
|
||||
RUN bee pack
|
||||
RUN mkdir -p /app/extracted && tar -zxvf oc-datacenter.tar.gz -C /app/extracted
|
||||
RUN sed -i 's/http:\/\/127.0.0.1:8080\/swagger\/swagger.json/swagger.json/g' /app/extracted/swagger/index.html
|
||||
@@ -36,6 +41,8 @@ RUN sed -i 's/http:\/\/127.0.0.1:8080\/swagger\/swagger.json/swagger.json/g' /ap
|
||||
|
||||
FROM golang:alpine
|
||||
|
||||
ENV KUBERNETES_SERVICE_HOST=$KUBERNETES_HOST
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/extracted/oc-datacenter /usr/bin/
|
||||
COPY --from=builder /app/extracted/swagger /app/swagger
|
||||
|
||||
21
Makefile
21
Makefile
@@ -6,6 +6,14 @@ build: clean
|
||||
run:
|
||||
bee run -gendoc=true -downdoc=true
|
||||
|
||||
purge:
|
||||
lsof -t -i:8092 | xargs kill | true
|
||||
|
||||
run-dev:
|
||||
bee generate routers && bee run -gendoc=true -downdoc=true -runmode=prod
|
||||
|
||||
dev: purge run-dev
|
||||
|
||||
debug:
|
||||
bee run -downdebug -gendebug
|
||||
|
||||
@@ -13,15 +21,20 @@ clean:
|
||||
rm -rf oc-datacenter.tar.gz
|
||||
|
||||
docker:
|
||||
DOCKER_BUILDKIT=1 docker build -t oc/oc-datacenter:0.0.1 -f Dockerfile .
|
||||
docker tag oc/oc-datacenter:0.0.1 oc/oc-datacenter:latest
|
||||
DOCKER_BUILDKIT=1 docker build -t oc-datacenter -f Dockerfile . --build-arg=HOST=$(HOST)
|
||||
docker tag oc-datacenter:latest oc/oc-datacenter:0.0.1
|
||||
|
||||
publish-kind:
|
||||
kind load docker-image oc/oc-datacenter:0.0.1 --name opencloud
|
||||
kind load docker-image oc/oc-datacenter:0.0.1 --name opencloud | true
|
||||
|
||||
publish-registry:
|
||||
@echo "TODO"
|
||||
|
||||
docker-deploy:
|
||||
docker compose up -d
|
||||
|
||||
run-docker: docker publish-kind publish-registry docker-deploy
|
||||
|
||||
all: docker publish-kind publish-registry
|
||||
|
||||
.PHONY: build run clean docker publish-kind publish-registry
|
||||
.PHONY: build run clean docker publish-kind publish-registry
|
||||
|
||||
55
README.md
55
README.md
@@ -7,9 +7,62 @@ To build :
|
||||
bee generate routers
|
||||
bee run -gendoc=true -downdoc=true
|
||||
|
||||
OR
|
||||
make dev
|
||||
|
||||
If default Swagger page is displayed instead of tyour api, change url in swagger/index.html file to :
|
||||
|
||||
url: "swagger.json"
|
||||
|
||||
Note on particular process :
|
||||
- set a bookin delete all related workflow booking before creating new ones. (no update of existing ones)
|
||||
- set a bookin delete all related workflow booking before creating new ones. (no update of existing ones)
|
||||
|
||||
## Admiralty
|
||||
|
||||
The routes in /admiralty will trigger actions on the DC's Kubernetes API to retrieve information on Admiralty resources.
|
||||
|
||||
### Targets
|
||||
|
||||
Remote clusters that can be used by Admiralty to delegate pods.
|
||||
|
||||
To set up a target Admiralty needs to associate a `secret` which contains an edited version of the target's `kubeconfig`.
|
||||
|
||||
Once the Target is set the remote cluster appears in the output of `kubectl get nodes` under the name `admiralty-<namespace>-<target name>-*`
|
||||
|
||||
**TODO** : We might need a way to test if an IP is associated to an admiralty target
|
||||
|
||||
# Docker Kube Settings
|
||||
|
||||
Set up your base64 key from your ~/.kube/config.
|
||||
Don't forget to set up your external IP in docker_datacenter.json
|
||||
## Admiralty
|
||||
|
||||
The routes in /admiralty will trigger actions on the DC's Kubernetes API to retrieve information on Admiralty resources.
|
||||
|
||||
### Targets
|
||||
|
||||
Remote clusters that can be used by Admiralty to delegate pods.
|
||||
|
||||
To set up a target Admiralty needs to associate a `secret` which contains an edited version of the target's `kubeconfig`.
|
||||
|
||||
Once the Target is set the remote cluster appears in the output of `kubectl get nodes` under the name `admiralty-<namespace>-<target name>-*`
|
||||
|
||||
**TODO** : We might need a way to test if an IP is associated to an admiralty target
|
||||
|
||||
# Docker Kube Settings
|
||||
|
||||
Set up your base64 key from your ~/.kube/config.
|
||||
Don't forget to set up your external IP in docker_datacenter.json
|
||||
## Admiralty
|
||||
|
||||
The routes in /admiralty will trigger actions on the DC's Kubernetes API to retrieve information on Admiralty resources.
|
||||
|
||||
### Targets
|
||||
|
||||
Remote clusters that can be used by Admiralty to delegate pods.
|
||||
|
||||
To set up a target Admiralty needs to associate a `secret` which contains an edited version of the target's `kubeconfig`.
|
||||
|
||||
Once the Target is set the remote cluster appears in the output of `kubectl get nodes` under the name `admiralty-<namespace>-<target name>-*`
|
||||
|
||||
**TODO** : We might need a way to test if an IP is associated to an admiralty target
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
appname = oc-datacenter
|
||||
httpport = 8080
|
||||
httpport = 8092
|
||||
runmode = dev
|
||||
autorender = false
|
||||
copyrequestbody = true
|
||||
@@ -7,4 +7,4 @@ EnableDocs = true
|
||||
sqlconn =
|
||||
|
||||
MONGO_URL = "mongodb://127.0.0.1:27017/beego-demo"
|
||||
MONGO_DATABASE = "DC_myDC-demo_06042021"
|
||||
MONGO_DATABASE = "DC_myDC-demo_06042021"
|
||||
24
conf/config.go
Normal file
24
conf/config.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package conf
|
||||
|
||||
import "sync"
|
||||
|
||||
type Config struct {
|
||||
Mode string
|
||||
KubeHost string
|
||||
KubePort string
|
||||
KubeCA string
|
||||
KubeCert string
|
||||
KubeData string
|
||||
MinioRootKey string
|
||||
MinioRootSecret string
|
||||
}
|
||||
|
||||
var instance *Config
|
||||
var once sync.Once
|
||||
|
||||
func GetConfig() *Config {
|
||||
once.Do(func() {
|
||||
instance = &Config{}
|
||||
})
|
||||
return instance
|
||||
}
|
||||
601
controllers/admiralty.go
Normal file
601
controllers/admiralty.go
Normal file
@@ -0,0 +1,601 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"oc-datacenter/conf"
|
||||
"oc-datacenter/infrastructure"
|
||||
"oc-datacenter/models"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
jwt "github.com/golang-jwt/jwt/v5"
|
||||
"gopkg.in/yaml.v2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
type KubeInfo struct {
|
||||
Url *string
|
||||
KubeCA *string
|
||||
KubeCert *string
|
||||
KubeKey *string
|
||||
}
|
||||
|
||||
type RemoteKubeconfig struct {
|
||||
Data *string
|
||||
}
|
||||
|
||||
type KubeUser struct {
|
||||
Name string
|
||||
User struct {
|
||||
Token string
|
||||
}
|
||||
}
|
||||
|
||||
type KubeconfigToken struct {
|
||||
ApiVersion string `yaml:"apiVersion"`
|
||||
Kind string `yaml:"kind"`
|
||||
Preferences string `yaml:"preferences"`
|
||||
CurrentContext string `yaml:"current-context"`
|
||||
Clusters []struct {
|
||||
Cluster struct {
|
||||
CA string `yaml:"certificate-authority-data"`
|
||||
Server string `yaml:"server"`
|
||||
} `yaml:"cluster"`
|
||||
Name string `yaml:"name"`
|
||||
} `yaml:"clusters"`
|
||||
Contexts []struct {
|
||||
Context struct {
|
||||
Cluster string `yaml:"cluster"`
|
||||
User string `yaml:"user"`
|
||||
} `yaml:"context"`
|
||||
Name string `yaml:"name"`
|
||||
} `yaml:"contexts"`
|
||||
Users []struct {
|
||||
Name string `yaml:"name"`
|
||||
User struct {
|
||||
Token string `yaml:"token"`
|
||||
} `yaml:"user"`
|
||||
} `yaml:"users"`
|
||||
}
|
||||
|
||||
// Operations about the admiralty objects of the datacenter
|
||||
type AdmiraltyController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// @Title GetAllTargets
|
||||
// @Description find all Admiralty Target
|
||||
// @Success 200
|
||||
// @router /targets [get]
|
||||
func (c *AdmiraltyController) GetAllTargets() {
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
HandleControllerErrors(c.Controller, 500, &err, nil)
|
||||
// c.Ctx.Output.SetStatus(500)
|
||||
// c.ServeJSON()
|
||||
// c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
|
||||
res, err := serv.GetTargets(c.Ctx.Request.Context())
|
||||
c.Data["json"] = res
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title GetOneTarget
|
||||
// @Description find one Admiralty Target
|
||||
// @Param id path string true "the name of the target to get"
|
||||
// @Success 200
|
||||
// @router /targets/:execution [get]
|
||||
func (c *AdmiraltyController) GetOneTarget() {
|
||||
id := c.Ctx.Input.Param(":execution")
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
|
||||
res, err := serv.GetTargets(c.Ctx.Request.Context())
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
id = "target-" + id
|
||||
found := slices.Contains(res, id)
|
||||
if !found {
|
||||
c.Ctx.Output.SetStatus(404)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
c.Data["json"] = id
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title DeleteAdmiraltySession
|
||||
// @Description find one Admiralty Target
|
||||
// @Param execution path string true "the name of the target to get"
|
||||
// @Success 200
|
||||
// @router /targets/:execution [delete]
|
||||
func (c *AdmiraltyController) DeleteAdmiraltySession() {
|
||||
id := c.Ctx.Input.Param(":execution")
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
|
||||
err = serv.DeleteNamespace(c.Ctx.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = id
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title CreateAdmiraltySource
|
||||
// @Description Create an Admiralty Source on remote cluster
|
||||
// @Param execution path string true "execution id of the workflow"
|
||||
// @Success 201
|
||||
// @router /source/:execution [post]
|
||||
func (c *AdmiraltyController) CreateAdmiraltySource() {
|
||||
|
||||
execution := c.Ctx.Input.Param(":execution")
|
||||
fmt.Println("execution :: ", execution)
|
||||
fmt.Println("input :: ", c.Ctx.Input)
|
||||
serv, err := infrastructure.NewKubernetesService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
res, err := serv.CreateAdmiraltySource(c.Ctx.Request.Context(), execution)
|
||||
if err != nil {
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
c.Ctx.Output.SetStatus(409)
|
||||
c.Data["json"] = map[string]string{"info": "A source already exists for this namespace : " + execution}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// TODO : Return a description of the created resource
|
||||
var respData map[string]interface{}
|
||||
err = json.Unmarshal(res, &respData)
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
c.Ctx.Output.SetStatus(201)
|
||||
c.Data["json"] = respData
|
||||
c.ServeJSON()
|
||||
|
||||
}
|
||||
|
||||
// @Title CreateAdmiraltyTarget
|
||||
// @Description Create an Admiralty Target in the namespace associated to the executionID
|
||||
// @Param execution path string true "execution id of the workflow"
|
||||
// @Param peer path string true "peerId of the peer the target points to"
|
||||
// @Success 201
|
||||
// @router /target/:execution/:peer [post]
|
||||
func (c *AdmiraltyController) CreateAdmiraltyTarget() {
|
||||
var data map[string]interface{}
|
||||
|
||||
execution := c.Ctx.Input.Param(":execution")
|
||||
peerId := c.Ctx.Input.Param(":peer")
|
||||
|
||||
if execution == "" || peerId == "" {
|
||||
c.Ctx.Output.SetStatus(400)
|
||||
c.Data["json"] = map[string]string{"error": "parameters can be empty " + "execution: " + execution + " peer: " + peerId}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := serv.CreateAdmiraltyTarget(c.Ctx.Request.Context(), execution, peerId)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
fmt.Println("Error while trying to create Admiralty target")
|
||||
fmt.Println(resp)
|
||||
fmt.Println(err)
|
||||
c.Ctx.Output.SetStatus(401)
|
||||
c.Data["json"] = map[string]string{"error": "Could not perform the action"}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(resp, &data)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
c.Ctx.Output.SetStatus(201)
|
||||
c.Data["json"] = data
|
||||
c.ServeJSON()
|
||||
|
||||
}
|
||||
|
||||
// @Title GetKubeSecret
|
||||
// @Description Retrieve the secret created from a Kubeconfig that will be associated to an Admiralty Target
|
||||
// @Param execution path string true "execution id of the workflow"
|
||||
// @Param peer path string true "UUID of the peer to which the resource is linked"
|
||||
// @Success 200
|
||||
// @router /secret/:execution/:peer [get]
|
||||
func (c *AdmiraltyController) GetKubeSecret() {
|
||||
var data map[string]interface{}
|
||||
|
||||
execution := c.Ctx.Input.Param(":execution")
|
||||
peerId := c.Ctx.Input.Param(":peer")
|
||||
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(), execution, peerId)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
c.Ctx.Output.SetStatus(404)
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(resp, &data)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.ServeJSON()
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = data
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title CreateKubeSecret
|
||||
// @Description Creat a secret from a Kubeconfig that will be associated to an Admiralty Target
|
||||
|
||||
// @Param execution path string true "execution id of the workflow"
|
||||
// @Param peer path string true "UUID of the peer to which the resource is linked"
|
||||
// @Param kubeconfig body controllers.RemoteKubeconfig true "Kubeconfig to use when creating secret"
|
||||
// @Success 201
|
||||
// @router /secret/:execution/:peer [post]
|
||||
func (c *AdmiraltyController) CreateKubeSecret() {
|
||||
var kubeconfig RemoteKubeconfig
|
||||
var respData map[string]interface{}
|
||||
|
||||
data := c.Ctx.Input.CopyBody(100000)
|
||||
|
||||
err := json.Unmarshal(data, &kubeconfig)
|
||||
if err != nil {
|
||||
fmt.Println("Error when retrieving the data for kubeconfig from request")
|
||||
fmt.Println(err)
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
execution := c.Ctx.Input.Param(":execution")
|
||||
peerId := c.Ctx.Input.Param(":peer")
|
||||
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := serv.CreateKubeconfigSecret(c.Ctx.Request.Context(), *kubeconfig.Data, execution, peerId)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(resp, &respData)
|
||||
c.Ctx.Output.SetStatus(201)
|
||||
c.Data["json"] = respData
|
||||
c.ServeJSON()
|
||||
|
||||
}
|
||||
|
||||
// @name GetAdmiraltyNodes
|
||||
// @description Allows user to test if an admiralty connection has already been established : Target and valid Secret set up on the local host and Source set up on remote host
|
||||
// @Param execution path string true "execution id of the workflow"
|
||||
// @Param peer path string true "UUID of the peer to which the resource is linked"
|
||||
// @Success 200
|
||||
// @router /node/:execution/:peer [get]
|
||||
func (c *AdmiraltyController) GetNodeReady() {
|
||||
var secret v1.Secret
|
||||
execution := c.Ctx.Input.Param(":execution")
|
||||
peerId := c.Ctx.Input.Param(":peer")
|
||||
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
node, err := serv.GetOneNode(c.Ctx.Request.Context(), execution, peerId)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
if node == nil {
|
||||
c.Ctx.Output.SetStatus(404)
|
||||
c.Data["json"] = map[string]string{
|
||||
"node": "the node for " + execution + " can't be found, make sure both target and source resources are set up on local and remote hosts",
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(), execution, peerId)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": "Nodes was up but the secret can't be found"}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// Extract JWT token RS265 encoded
|
||||
var editedKubeconfig map[string]interface{}
|
||||
json.Unmarshal(resp, &secret)
|
||||
byteEditedKubeconfig := secret.Data["config"]
|
||||
err = yaml.Unmarshal(byteEditedKubeconfig, &editedKubeconfig)
|
||||
// err = json.Unmarshal(byteEditedKubeconfig,&editedKubeconfig)
|
||||
if err != nil {
|
||||
fmt.Println("Error while retrieving the kubeconfig from secret-", execution)
|
||||
fmt.Println(err)
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = err
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
token, err := retrieveTokenFromKonfig(editedKubeconfig)
|
||||
if err != nil {
|
||||
fmt.Println("Error while trying to retrieve token for kubeconfing")
|
||||
fmt.Println(err)
|
||||
HandleControllerErrors(c.Controller, 500, &err, nil)
|
||||
}
|
||||
|
||||
// Decode token
|
||||
isExpired, err := isTokenExpired(token)
|
||||
if err != nil {
|
||||
fmt.Println("Error veryfing token's expiration")
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = err
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
if *isExpired {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"token": "token in the secret is expired and must be regenerated",
|
||||
"node": node,
|
||||
}
|
||||
c.Ctx.Output.SetStatus(410)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{"node": node, "token": true}
|
||||
c.ServeJSON()
|
||||
|
||||
}
|
||||
|
||||
func retrieveTokenFromKonfig(editedKubeconfig map[string]interface{}) (string, error) {
|
||||
var kubeUsers []KubeUser
|
||||
b, err := yaml.Marshal(editedKubeconfig["users"])
|
||||
if err != nil {
|
||||
fmt.Println("Error while retrieving the users attribute from the Kubeconfig")
|
||||
fmt.Println(err)
|
||||
return "", err
|
||||
}
|
||||
err = yaml.Unmarshal(b, &kubeUsers)
|
||||
if err != nil {
|
||||
fmt.Println("Error while unmarshalling users attribute from kubeconfig")
|
||||
fmt.Println(err)
|
||||
return "", nil
|
||||
}
|
||||
fmt.Println(kubeUsers)
|
||||
token := kubeUsers[0].User.Token
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func isTokenExpired(token string) (*bool, error) {
|
||||
logger := oclib.GetLogger()
|
||||
|
||||
t, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
|
||||
if err != nil {
|
||||
fmt.Println("couldn't decode token")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
expiration, err := t.Claims.GetExpirationTime()
|
||||
if err != nil {
|
||||
fmt.Println("Error while checking token's expiration time")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Debug().Msg("Expiration date : " + expiration.UTC().Format("2006-01-02T15:04:05"))
|
||||
logger.Debug().Msg(fmt.Sprint("Now : ", time.Now().Unix()))
|
||||
logger.Debug().Msg(fmt.Sprint("Token : ", expiration.Unix()))
|
||||
|
||||
expired := expiration.Unix() < time.Now().Unix()
|
||||
|
||||
return &expired, nil
|
||||
}
|
||||
|
||||
// @name Get Admiralty Kubeconfig
|
||||
// @description Retrieve a kubeconfig from the host with the token to authenticate as the SA from the namespace identified with execution id
|
||||
|
||||
// @Param execution path string true "execution id of the workflow"
|
||||
// @Success 200
|
||||
// @router /kubeconfig/:execution [get]
|
||||
func (c *AdmiraltyController) GetAdmiraltyKubeconfig() {
|
||||
|
||||
execution := c.Ctx.Input.Param(":execution")
|
||||
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
generatedToken, err := serv.GenerateToken(c.Ctx.Request.Context(), execution, 3600)
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't generate a token for ns-", execution)
|
||||
fmt.Println(err)
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
kubeconfig, err := NewHostKubeWithToken(generatedToken)
|
||||
if err != nil {
|
||||
fmt.Println("Could not retrieve the Kubeconfig edited with token")
|
||||
fmt.Println(err)
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
b, err := json.Marshal(kubeconfig)
|
||||
if err != nil {
|
||||
fmt.Println("Error while marshalling kubeconfig")
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
c.Data["json"] = map[string]string{"error": err.Error()}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
encodedKubeconfig := base64.StdEncoding.EncodeToString(b)
|
||||
c.Data["json"] = map[string]string{
|
||||
"data": encodedKubeconfig,
|
||||
}
|
||||
json.NewEncoder(c.Ctx.ResponseWriter)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func NewHostKubeWithToken(token string) (*models.KubeConfigValue, error) {
|
||||
if len(token) == 0 {
|
||||
return nil, fmt.Errorf("you didn't provide a token to be inserted in the Kubeconfig")
|
||||
}
|
||||
|
||||
encodedCA := base64.StdEncoding.EncodeToString([]byte(conf.GetConfig().KubeCA))
|
||||
|
||||
hostKube := models.KubeConfigValue{
|
||||
APIVersion: "v1",
|
||||
CurrentContext: "default",
|
||||
Kind: "Config",
|
||||
Preferences: struct{}{},
|
||||
Clusters: []models.KubeconfigNamedCluster{
|
||||
{
|
||||
Name: "default",
|
||||
Cluster: models.KubeconfigCluster{
|
||||
Server: "https://" + conf.GetConfig().KubeHost + ":6443",
|
||||
CertificateAuthorityData: encodedCA,
|
||||
},
|
||||
},
|
||||
},
|
||||
Contexts: []models.KubeconfigNamedContext{
|
||||
{
|
||||
Name: "default",
|
||||
Context: models.KubeconfigContext{
|
||||
Cluster: "default",
|
||||
User: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
Users: []models.KubeconfigUser{
|
||||
{
|
||||
Name: "default",
|
||||
User: models.KubeconfigUserKeyPair{
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &hostKube, nil
|
||||
}
|
||||
@@ -4,13 +4,19 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"oc-datacenter/infrastructure"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
b "cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
||||
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"github.com/gorilla/websocket"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
@@ -19,10 +25,42 @@ type BookingController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
var BookingExample booking.Booking
|
||||
|
||||
// @Title Search
|
||||
// @Description search bookings by execution
|
||||
// @Param id path string true "id execution"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {workspace} models.workspace
|
||||
// @router /search/execution/:id [get]
|
||||
func (o *BookingController) ExecutionSearch() {
|
||||
/*
|
||||
* This is a sample of how to use the search function
|
||||
* The search function is used to search for data in the database
|
||||
* The search function takes in a filter and a data type
|
||||
* The filter is a struct that contains the search parameters
|
||||
* The data type is an enum that specifies the type of data to search for
|
||||
* The search function returns a list of data that matches the filter
|
||||
* The data is then returned as a json object
|
||||
*/
|
||||
// store and return Id or post with UUID
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
isDraft := o.Ctx.Input.Query("is_draft")
|
||||
f := dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{ // filter by name if no filters are provided
|
||||
"execution_id": {{Operator: dbs.EQUAL.String(), Value: id}},
|
||||
},
|
||||
}
|
||||
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).Search(&f, "", isDraft == "true")
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title Search
|
||||
// @Description search bookings
|
||||
// @Param start_date path string true "the word search you want to get"
|
||||
// @Param end_date path string true "the word search you want to get"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {workspace} models.workspace
|
||||
// @router /search/:start_date/:end_date [get]
|
||||
func (o *BookingController) Search() {
|
||||
@@ -36,25 +74,30 @@ func (o *BookingController) Search() {
|
||||
* The data is then returned as a json object
|
||||
*/
|
||||
// store and return Id or post with UUID
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
start_date, _ := time.Parse("2006-01-02", o.Ctx.Input.Param(":start_date"))
|
||||
end_date, _ := time.Parse("2006-01-02", o.Ctx.Input.Param(":end_date"))
|
||||
isDraft := o.Ctx.Input.Query("is_draft")
|
||||
sd := primitive.NewDateTimeFromTime(start_date)
|
||||
ed := primitive.NewDateTimeFromTime(end_date)
|
||||
f := dbs.Filters{
|
||||
And: map[string][]dbs.Filter{
|
||||
"workflowexecution.execution_date": {{Operator: "gte", Value: sd}, {Operator: "lte", Value: ed}},
|
||||
"execution_date": {{Operator: "gte", Value: sd}, {Operator: "lte", Value: ed}},
|
||||
},
|
||||
}
|
||||
o.Data["json"] = oclib.Search(&f, "", oclib.LibDataEnum(oclib.BOOKING))
|
||||
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).Search(&f, "", isDraft == "true")
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title GetAll
|
||||
// @Description find booking by id
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {booking} models.booking
|
||||
// @router / [get]
|
||||
func (o *BookingController) GetAll() {
|
||||
o.Data["json"] = oclib.LoadAll(oclib.LibDataEnum(oclib.BOOKING))
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
isDraft := o.Ctx.Input.Query("is_draft")
|
||||
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).LoadAll(isDraft == "true")
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -64,8 +107,64 @@ func (o *BookingController) GetAll() {
|
||||
// @Success 200 {booking} models.booking
|
||||
// @router /:id [get]
|
||||
func (o *BookingController) Get() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
o.Data["json"] = oclib.LoadOne(oclib.LibDataEnum(oclib.BOOKING), id)
|
||||
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).LoadOne(id)
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool { return true }, // allow all origins
|
||||
}
|
||||
|
||||
// @Title Log
|
||||
// @Description find booking by id
|
||||
// @Param id path string true "the id you want to get"
|
||||
// @Success 200 {booking} models.booking
|
||||
// @router /:id [get]
|
||||
func (o *BookingController) Log() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
conn, err := upgrader.Upgrade(o.Ctx.ResponseWriter, o.Ctx.Request, nil)
|
||||
if err != nil {
|
||||
o.Ctx.WriteString("WebSocket upgrade failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
infrastructure.NewPrometheusService().Stream(id, 1*time.Second, user, peerID, groups, conn)
|
||||
}
|
||||
|
||||
// @Title Update
|
||||
// @Description create computes
|
||||
// @Param id path string true "the compute id you want to get"
|
||||
// @Param body body models.compute true "The compute content"
|
||||
// @Success 200 {compute} models.compute
|
||||
// @router /:id [put]
|
||||
func (o *BookingController) Put() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
// store and return Id or post with UUID
|
||||
var res map[string]interface{}
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
book := oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).LoadOne(id)
|
||||
if book.Code != 200 {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": book.Code,
|
||||
"error": book.Err,
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
booking := book.Data.(*booking.Booking)
|
||||
if time.Now().After(booking.ExpectedStartDate) {
|
||||
o.Data["json"] = oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).UpdateOne(res, id)
|
||||
} else {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": 409,
|
||||
"error": "booking is not already started",
|
||||
}
|
||||
}
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -74,6 +173,7 @@ func (o *BookingController) Get() {
|
||||
// @Param id path string "id of the datacenter"
|
||||
// @Param start_date path string "the booking start date" format "2006-01-02T15:04:05"
|
||||
// @Param end_date path string "the booking end date" format "2006-01-02T15:04:05"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {object} models.object
|
||||
// @router /check/:id/:start_date/:end_date [get]
|
||||
func (o *BookingController) Check() {
|
||||
@@ -81,7 +181,7 @@ func (o *BookingController) Check() {
|
||||
* This function is used to check if a booking is available for a specific datacenter.
|
||||
* It takes the following parameters:
|
||||
* - id: the id of the datacenter
|
||||
* - start_date: the start date of the booking
|
||||
* - start_date: the start date of the booking/search/execution/:id
|
||||
* - end_date: the end date of the booking
|
||||
*/
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
@@ -96,12 +196,10 @@ func (o *BookingController) Check() {
|
||||
"error": errors.New("invalid date format"),
|
||||
}
|
||||
} else {
|
||||
booking := &b.Booking{} // create a new booking object
|
||||
isAvailable, err2 := booking.CheckBooking(id, date, &date2) // check if the booking is available
|
||||
fmt.Println(isAvailable, err2)
|
||||
bks := &booking.Booking{} // create a new booking object
|
||||
code := 200
|
||||
err := ""
|
||||
if !isAvailable {
|
||||
if isAvailable, err2 := bks.Check(id, date, &date2, 1); !isAvailable {
|
||||
code = 409
|
||||
err = "booking not available"
|
||||
if err2 != nil {
|
||||
@@ -110,7 +208,7 @@ func (o *BookingController) Check() {
|
||||
}
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"is_available": isAvailable,
|
||||
"is_available": true,
|
||||
},
|
||||
"code": code,
|
||||
"error": err,
|
||||
@@ -119,9 +217,10 @@ func (o *BookingController) Check() {
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title Post
|
||||
// @Title Post.
|
||||
// @Description create booking
|
||||
// @Param booking body string true "the booking you want to post"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {object} models.object
|
||||
// @router / [post]
|
||||
func (o *BookingController) Post() {
|
||||
@@ -133,15 +232,56 @@ func (o *BookingController) Post() {
|
||||
* - datacenter_resource_id: the id of the datacenter
|
||||
* - workflow_execution: the workflow execution
|
||||
*/
|
||||
var resp workflow_execution.WorkflowExecutions
|
||||
json.Unmarshal(o.Ctx.Input.CopyBody(10000), &resp)
|
||||
dc_id := resp.ResourceID
|
||||
var resp booking.Booking
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
err := json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &resp)
|
||||
if err != nil {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": 422,
|
||||
"error": err,
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
if resp.ResourceType == tools.COMPUTE_RESOURCE {
|
||||
// later should check... health for any such as docker...
|
||||
res := oclib.NewRequest(oclib.LibDataEnum(oclib.COMPUTE_RESOURCE), user, peerID, groups, nil).LoadOne(resp.ResourceID)
|
||||
if res.Err != "" {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": res.Code,
|
||||
"error": res.Err,
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
/*serv, err := infrastructure.NewServiceByType(res.ToComputeResource().Infrastructure.String())
|
||||
if err != nil {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": 500,
|
||||
"error": err,
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
if err := serv.CheckHealth(); err != nil {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": 500,
|
||||
"error": err,
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}*/
|
||||
}
|
||||
// delete all previous bookings
|
||||
fmt.Println("Deleting previous bookings", resp)
|
||||
res := oclib.Search(&dbs.Filters{And: map[string][]dbs.Filter{
|
||||
"workflowexecution.workflow_id": {{Operator: dbs.EQUAL.String(), Value: resp.WorkflowID}},
|
||||
"compute_resource_id": {{Operator: dbs.EQUAL.String(), Value: dc_id}},
|
||||
}}, "", oclib.LibDataEnum(oclib.BOOKING))
|
||||
isDraft := o.Ctx.Input.Query("is_draft")
|
||||
res := oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).Search(&dbs.Filters{And: map[string][]dbs.Filter{
|
||||
"workflow_id": {{Operator: dbs.EQUAL.String(), Value: resp.WorkflowID}},
|
||||
"resource_id": {{Operator: dbs.EQUAL.String(), Value: resp.ResourceID}},
|
||||
}}, "", isDraft == "true")
|
||||
if res.Code != 200 {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
@@ -152,37 +292,181 @@ func (o *BookingController) Post() {
|
||||
return
|
||||
}
|
||||
for _, b := range res.Data { // delete all previous bookings
|
||||
oclib.DeleteOne(oclib.LibDataEnum(oclib.BOOKING), b.GetID())
|
||||
oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).DeleteOne(b.GetID())
|
||||
}
|
||||
books := make([]interface{}, 0)
|
||||
errormsg := ""
|
||||
for _, exec := range resp.Executions { // create new bookings
|
||||
if ok, _ := (&b.Booking{}).CheckBooking(dc_id, *exec.ExecDate, exec.EndDate); !ok {
|
||||
res.Err += " -> the booking from " + exec.ExecDate.String() + " is already taken."
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": res.Code,
|
||||
"error": res.Err + " -> the booking from " + exec.ExecDate.String() + " is already taken.",
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
new := &b.Booking{
|
||||
ComputeResourceID: dc_id,
|
||||
WorkflowExecution: *exec,
|
||||
}
|
||||
// store the booking
|
||||
b := oclib.StoreOne(oclib.LibDataEnum(oclib.BOOKING), new.Serialize())
|
||||
if b.Code == 200 {
|
||||
books = append(books, b.Data)
|
||||
} else {
|
||||
errormsg += " -> " + b.Err
|
||||
b := oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil).StoreOne(resp.Serialize(&resp))
|
||||
if b.Code != 200 {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": b.Code,
|
||||
"error": b.Err,
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
if b.Data.(*booking.Booking).ResourceType == tools.COMPUTE_RESOURCE {
|
||||
go func() {
|
||||
time.Sleep(time.Until(b.Data.(*booking.Booking).ExpectedStartDate))
|
||||
infrastructure.NewPrometheusService().Stream(b.Data.GetID(), 1*time.Second, user, peerID, groups, nil)
|
||||
}()
|
||||
}
|
||||
|
||||
if err := o.createNamespace(resp.ExecutionsID); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": books,
|
||||
"data": []interface{}{b},
|
||||
"code": 200,
|
||||
"error": errormsg,
|
||||
"error": "",
|
||||
}
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title ExtendForNamespace
|
||||
// @Description ExtendForNamespace booking
|
||||
// @Param namespace path string "targetted namespace"
|
||||
// @Param resource_id path string "resource id"
|
||||
// @Param end_date path string "the booking end date" format "2006-01-02T15:04:05"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {object} models.object
|
||||
// @router /extend/:resource_id/from_namespace/:namespace/to/:duration [post]
|
||||
func (o *BookingController) ExtendForNamespace() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
resourceID := o.Ctx.Input.Param(":resource_id")
|
||||
namespace := o.Ctx.Input.Param(":namespace")
|
||||
duration, err := strconv.Atoi(o.Ctx.Input.Param(":duration"))
|
||||
if err != nil {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"is_available": false,
|
||||
},
|
||||
"code": 400,
|
||||
"error": errors.New("invalid date format"),
|
||||
}
|
||||
} else {
|
||||
o.extend(duration, resourceID, "executions_id", namespace, user, peerID, groups)
|
||||
}
|
||||
}
|
||||
|
||||
// @Title ExtendForExecution
|
||||
// @Description ExtendForExecution booking
|
||||
// @Param namespace path string "targetted namespace"
|
||||
// @Param resource_id path string "resource id"
|
||||
// @Param end_date path string "the booking end date" format "2006-01-02T15:04:05"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {object} models.object
|
||||
// @router /extend/:resource_id/from_execution/:execution_id/to/:duration [post]
|
||||
func (o *BookingController) ExtendForExecution() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
resourceID := o.Ctx.Input.Param(":resource_id")
|
||||
executionID := o.Ctx.Input.Param(":execution_id")
|
||||
duration, err := strconv.Atoi(o.Ctx.Input.Param(":duration"))
|
||||
if err != nil {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"is_available": false,
|
||||
},
|
||||
"code": 400,
|
||||
"error": errors.New("invalid date format"),
|
||||
}
|
||||
} else {
|
||||
o.extend(duration, resourceID, "execution_id", executionID, user, peerID, groups)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *BookingController) extend(duration int, resourceID string, key string, namespace string, user string, peerID string, groups []string) {
|
||||
/*
|
||||
* This function is used to check if a booking is available for a specific datacenter.
|
||||
* It takes the following parameters:
|
||||
* - id: the id of the datacenter
|
||||
* - start_date: the start date of the booking/search/execution/:id
|
||||
* - end_date: the end date of the booking
|
||||
*/
|
||||
|
||||
req := oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil)
|
||||
res := req.Search(&dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"expected_end_date": {
|
||||
{Operator: dbs.GTE.String(), Value: time.Now()},
|
||||
{Operator: dbs.EQUAL.String(), Value: bson.TypeNull},
|
||||
},
|
||||
},
|
||||
And: map[string][]dbs.Filter{
|
||||
"resource_id": {{Operator: dbs.EQUAL.String(), Value: resourceID}},
|
||||
key: {{Operator: dbs.EQUAL.String(), Value: namespace}},
|
||||
"expected_start_date": {{Operator: dbs.GTE.String(), Value: time.Now()}},
|
||||
},
|
||||
}, "", false)
|
||||
if res.Err == "" && len(res.Data) > 0 {
|
||||
var id string
|
||||
datas := []utils.DBObject{}
|
||||
for _, b := range res.Data {
|
||||
book := b.(*booking.Booking)
|
||||
if book.ExpectedEndDate != nil {
|
||||
bb := book.ExpectedEndDate.Add(time.Duration(duration) * time.Second)
|
||||
if isAvailable, err := (&booking.Booking{}).Check(id, (*book.ExpectedEndDate).Add(1*time.Second), &bb, 1); isAvailable && err == nil {
|
||||
book.ExpectedEndDate = &bb
|
||||
result := req.UpdateOne(book.Serialize(book), book.GetID())
|
||||
datas = append(datas, result.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": datas,
|
||||
"code": 200,
|
||||
"error": "",
|
||||
}
|
||||
o.ServeJSON()
|
||||
return
|
||||
} else if res.Err == "" {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
"is_available": false,
|
||||
},
|
||||
"code": 400,
|
||||
"error": errors.New("can't find any booking to extend"),
|
||||
}
|
||||
} else {
|
||||
o.Data["json"] = res
|
||||
}
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
func (o *BookingController) createNamespace(ns string) error {
|
||||
/*
|
||||
* This function is used to create a namespace.
|
||||
* It takes the following parameters:
|
||||
* - ns: the namespace you want to create
|
||||
*/
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
err = serv.CreateNamespace(o.Ctx.Request.Context(), ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = serv.CreateServiceAccount(o.Ctx.Request.Context(), ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role := "argo-role"
|
||||
err = serv.CreateRole(o.Ctx.Request.Context(), ns, role,
|
||||
[][]string{
|
||||
{"coordination.k8s.io"},
|
||||
{""},
|
||||
{""}},
|
||||
[][]string{
|
||||
{"leases"},
|
||||
{"secrets"},
|
||||
{"pods"}},
|
||||
[][]string{
|
||||
{"get", "create", "update"},
|
||||
{"get"},
|
||||
{"patch"}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return serv.CreateRoleBinding(o.Ctx.Request.Context(), ns, "argo-role-binding", role)
|
||||
}
|
||||
|
||||
85
controllers/datacenter.go
Normal file
85
controllers/datacenter.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// Operations about workspace
|
||||
type DatacenterController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// @Title GetAll
|
||||
// @Description find booking by id
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {booking} models.booking
|
||||
// @router / [get]
|
||||
func (o *DatacenterController) GetAll() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
isDraft := o.Ctx.Input.Query("is_draft")
|
||||
storages := oclib.NewRequest(oclib.LibDataEnum(oclib.STORAGE_RESOURCE), user, peerID, groups, nil).Search(&dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"abstractinstanciatedresource.abstractresource.abstractobject.creator_id": {{Operator: dbs.EQUAL.String(), Value: peerID}},
|
||||
},
|
||||
}, "", isDraft == "true")
|
||||
computes := oclib.NewRequest(oclib.LibDataEnum(oclib.COMPUTE_RESOURCE), user, peerID, groups, nil).Search(&dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"abstractinstanciatedresource.abstractresource.abstractobject.creator_id": {{Operator: dbs.EQUAL.String(), Value: peerID}},
|
||||
},
|
||||
}, "", isDraft == "true")
|
||||
storages.Data = append(storages.Data, computes.Data...)
|
||||
if storages.Err != "" {
|
||||
storages.Err += " - " + computes.Err
|
||||
}
|
||||
o.Data["json"] = storages
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title Get
|
||||
// @Description find booking by id
|
||||
// @Param id path string true "the id you want to get"
|
||||
// @Param is_draft query string false "draft wished"
|
||||
// @Success 200 {booking} models.booking
|
||||
// @router /:id [get]
|
||||
func (o *DatacenterController) Get() {
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
isDraft := o.Ctx.Input.Query("is_draft")
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
storages := oclib.NewRequest(oclib.LibDataEnum(oclib.STORAGE_RESOURCE), user, peerID, groups, nil).Search(&dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"abstractinstanciatedresource.abstractresource.abstractobject.id": {{Operator: dbs.EQUAL.String(), Value: id}},
|
||||
"abstractinstanciatedresource.abstractresource.abstractobject.creator_id": {{Operator: dbs.EQUAL.String(), Value: peerID}},
|
||||
},
|
||||
}, "", isDraft == "true")
|
||||
if len(storages.Data) == 0 {
|
||||
computes := oclib.NewRequest(oclib.LibDataEnum(oclib.COMPUTE_RESOURCE), user, peerID, groups, nil).Search(&dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"abstractinstanciatedresource.abstractresource.abstractobject.id": {{Operator: dbs.EQUAL.String(), Value: id}},
|
||||
"abstractinstanciatedresource.abstractresource.abstractobject.creator_id": {{Operator: dbs.EQUAL.String(), Value: peerID}},
|
||||
},
|
||||
}, "", isDraft == "true")
|
||||
if len(computes.Data) == 0 {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
"code": computes.Code,
|
||||
"err": computes.Err,
|
||||
}
|
||||
} else {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": computes.Data[0],
|
||||
"code": computes.Code,
|
||||
"err": computes.Err,
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": storages.Data[0],
|
||||
"code": storages.Code,
|
||||
"err": storages.Err,
|
||||
}
|
||||
}
|
||||
o.ServeJSON()
|
||||
}
|
||||
21
controllers/error_handler.go
Normal file
21
controllers/error_handler.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
func HandleControllerErrors(c beego.Controller, code int, err *error, data *map[string]interface{}, messages ...string) {
|
||||
for _, mess := range messages {
|
||||
fmt.Println(mess)
|
||||
}
|
||||
if data != nil {
|
||||
c.Data["json"] = data
|
||||
}
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]string{"error": (*err).Error()}
|
||||
}
|
||||
c.Ctx.Output.SetStatus(code)
|
||||
c.ServeJSON()
|
||||
}
|
||||
122
controllers/minio.go
Normal file
122
controllers/minio.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"oc-datacenter/infrastructure"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/models/live"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type MinioController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
|
||||
// @Title CreateServiceAccounnt
|
||||
// @Description Add a new ServiceAccount to a Minio server using its ID and an execution ID
|
||||
// @Success 200
|
||||
// @Param executions path string true "The executionsID of the execution"
|
||||
// @Param minioId path string true "The ID of the Minio you want to reach"
|
||||
// @router /serviceaccount/:minioId/:executions
|
||||
func (m *MinioController) CreateServiceAccount() {
|
||||
_, peerID, _ := oclib.ExtractTokenInfo(*m.Ctx.Request)
|
||||
// This part is solely for dev purposes and should be removed once test on
|
||||
|
||||
|
||||
executionsId := m.Ctx.Input.Param(":executions")
|
||||
minioId := m.Ctx.Input.Param(":minioId")
|
||||
|
||||
// retrieve the live storage with the minioId
|
||||
s := oclib.NewRequest(oclib.LibDataEnum(oclib.STORAGE_RESOURCE), "", "", []string{}, nil).LoadOne(minioId)
|
||||
if s.Err != "" {
|
||||
m.Ctx.Output.SetStatus(400)
|
||||
m.Data["json"] = map[string]interface{}{"error":s.Err}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
live := findLiveStorage(minioId, peerID)
|
||||
if live == nil {
|
||||
m.Ctx.Output.SetStatus(404)
|
||||
m.Data["json"] = map[string]interface{}{"error":"could not find the Minio instance " + s.Err}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
url := live.Source
|
||||
service := infrastructure.NewMinioService(url)
|
||||
|
||||
// call the method ctrating the svcacc
|
||||
err := service.CreateClient()
|
||||
if err != nil {
|
||||
m.Ctx.Output.SetStatus(500)
|
||||
m.Data["json"] = map[string]interface{}{"error":"could not create the client for " + minioId + " : " + err.Error()}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
access, secret, err := service.CreateCredentials(executionsId)
|
||||
if err != nil {
|
||||
m.Ctx.Output.SetStatus(500)
|
||||
m.Data["json"] = map[string]interface{}{"error":"could not create the service account for " + minioId + " : " + err.Error()}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// test if the namespace exists
|
||||
k, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
m.Ctx.Output.SetStatus(500)
|
||||
m.Data["json"] = map[string]string{"error": err.Error()}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := k.GetNamespace(m.Ctx.Request.Context(), executionsId)
|
||||
if ns == nil {
|
||||
m.Ctx.Output.SetStatus(403)
|
||||
m.Data["json"] = map[string]string{"error":"Could not find the namespace corresponding to executionsID " + executionsId}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
m.Ctx.Output.SetStatus(500)
|
||||
m.Data["json"] = map[string]string{"error": "Error when trying to check if namespace " + executionsId + " exists : " + err.Error()}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// store the credentials in the namespace
|
||||
err = k.CreateSecret(m.Ctx.Request.Context(), minioId, executionsId, access, secret)
|
||||
if err != nil {
|
||||
m.Ctx.Output.SetStatus(500)
|
||||
m.Data["json"] = map[string]string{"error": "Error when storing Minio serviceAccount credentials in namespace " + executionsId + " exists : " + err.Error()}
|
||||
m.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
m.Data["json"] = map[string]string{"success": "created secret " + executionsId + "-secret-sa in namespace ns-" + executionsId}
|
||||
m.ServeJSON()
|
||||
}
|
||||
|
||||
func findLiveStorage(storageId string, peerId string) *live.LiveStorage {
|
||||
res := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_STORAGE),"",peerId,[]string{},nil).LoadAll(false)
|
||||
if res.Err != "" {
|
||||
l := oclib.GetLogger()
|
||||
l.Error().Msg(res.Err)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, dbo := range res.Data {
|
||||
r := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_STORAGE),"","",[]string{},nil).LoadOne(dbo.GetID())
|
||||
l := r.ToLiveStorage()
|
||||
for _, id := range l.ResourcesID {
|
||||
if id == storageId {
|
||||
return l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
53
controllers/session.go
Normal file
53
controllers/session.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"oc-datacenter/infrastructure"
|
||||
"strconv"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type SessionController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// @Title GetToken
|
||||
// @Description find booking by id
|
||||
// @Param id path string "id of the datacenter"
|
||||
// @Param duration path string "duration of the token"
|
||||
// @Success 200 {booking} models.booking
|
||||
// @router /token/:id/:duration [get]
|
||||
func (o *SessionController) GetToken() {
|
||||
id := o.Ctx.Input.Param(":id")
|
||||
durationSTR := o.Ctx.Input.Param(":duration")
|
||||
|
||||
duration, err := strconv.Atoi(durationSTR)
|
||||
if err != nil {
|
||||
// change code to 400
|
||||
o.Ctx.Output.SetStatus(400)
|
||||
o.Data["json"] = map[string]string{"error": "duration invalid"}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
serv, err := infrastructure.NewService()
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
o.Ctx.Output.SetStatus(500)
|
||||
o.Data["json"] = map[string]string{"error": err.Error()}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
fmt.Println("BLAPO", id, duration)
|
||||
token, err := serv.GenerateToken(o.Ctx.Request.Context(), id, duration)
|
||||
if err != nil {
|
||||
// change code to 500
|
||||
o.Ctx.Output.SetStatus(500)
|
||||
o.Data["json"] = map[string]string{"error": err.Error()}
|
||||
o.ServeJSON()
|
||||
return
|
||||
}
|
||||
o.Data["json"] = token
|
||||
o.ServeJSON()
|
||||
}
|
||||
@@ -15,7 +15,10 @@ type VersionController struct {
|
||||
// @Success 200
|
||||
// @router / [get]
|
||||
func (c *VersionController) GetAll() {
|
||||
c.Data["json"] = map[string]string{"version": "1"}
|
||||
c.Data["json"] = map[string]string{
|
||||
"service": "oc-datacenter",
|
||||
"version": "1",
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"port": 8080,
|
||||
"MONGO_URL":"mongodb://localhost:27017/",
|
||||
"MONGO_DATABASE":"DC_myDC"
|
||||
"MONGO_URL": "mongodb://mongo:27017/",
|
||||
"NATS_URL": "nats://localhost:4222",
|
||||
"MONGO_DATABASE": "DC_myDC",
|
||||
"KUBERNETES_SERVICE_HOST": "172.16.0.183",
|
||||
"port": "8092"
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
version: '3.4'
|
||||
|
||||
services:
|
||||
mongo:
|
||||
image: 'mongo:latest'
|
||||
networks:
|
||||
- catalog
|
||||
ports:
|
||||
- 27017:27017
|
||||
container_name: mongo
|
||||
volumes:
|
||||
- oc-catalog-data:/data/db
|
||||
- oc-catalog-data:/data/configdb
|
||||
|
||||
mongo-express:
|
||||
image: "mongo-express:latest"
|
||||
restart: always
|
||||
depends_on:
|
||||
- mongo
|
||||
networks:
|
||||
- catalog
|
||||
ports:
|
||||
- 8081:8081
|
||||
environment:
|
||||
- ME_CONFIG_BASICAUTH_USERNAME=test
|
||||
- ME_CONFIG_BASICAUTH_PASSWORD=test
|
||||
|
||||
volumes:
|
||||
oc-catalog-data:
|
||||
|
||||
networks:
|
||||
catalog:
|
||||
external: true
|
||||
# name: catalog
|
||||
@@ -2,6 +2,9 @@ version: '3.4'
|
||||
|
||||
services:
|
||||
oc-datacenter:
|
||||
env_file:
|
||||
- path: ./env.env
|
||||
required: false
|
||||
environment:
|
||||
- MONGO_DATABASE=DC_myDC
|
||||
image: 'oc-datacenter:latest'
|
||||
@@ -10,14 +13,17 @@ services:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.datacenter.entrypoints=web"
|
||||
- "traefik.http.middlewares.auth.forwardauth.address=http://oc-auth:8080/oc/forward"
|
||||
- "traefik.http.routers.workflow.rule=PathPrefix(/datacenter)"
|
||||
- "traefik.http.routers.datacenter.tls=false"
|
||||
- "traefik.http.routers.datacenter.middlewares=auth"
|
||||
- "traefik.http.routers.datacenter.rule=PathPrefix(`/datacenter`)"
|
||||
- "traefik.http.services.datacenter.loadbalancer.server.port=8080"
|
||||
- "traefik.http.middlewares.datacenter-rewrite.replacepathregex.regex=^/datacenter(.*)"
|
||||
- "traefik.http.middlewares.datacenter-rewrite.replacepathregex.replacement=/oc$$1"
|
||||
- "traefik.http.routers.datacenter.middlewares=datacenter-rewrite"
|
||||
- "traefik.http.middlewares.datacenter.forwardauth.address=http://oc-auth:8080/oc/forward"
|
||||
container_name: oc-datacenter
|
||||
networks:
|
||||
- catalog
|
||||
- oc
|
||||
|
||||
|
||||
networks:
|
||||
catalog:
|
||||
oc:
|
||||
external: true
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"MONGO_URL":"mongodb://mongo:27017/",
|
||||
"NATS_URL":"nats://nats:4222",
|
||||
"MONGO_DATABASE":"DC_myDC"
|
||||
"MONGO_DATABASE":"DC_myDC"
|
||||
}
|
||||
21
docs/admiralty_setup.puml
Normal file
21
docs/admiralty_setup.puml
Normal file
@@ -0,0 +1,21 @@
|
||||
@startuml
|
||||
|
||||
boundary "oc-workflow" as workflow
|
||||
boundary "oc-monitord" as monitord
|
||||
boundary "local oc-datacenter" as locdc
|
||||
boundary "remote oc-datacenter" as rocdc
|
||||
|
||||
workflow --> locdc : POST /booking/ {booking object}
|
||||
locdc --> locdc : create Namespace + ServiceAccount
|
||||
workflow --> rocdc : POST /boking/
|
||||
rocdc --> rocdc : create \nNamespace + \nServiceAccount
|
||||
monitord --> monitord : retrieves a Workflow to execute
|
||||
monitord --> monitord : workflow needs repartited execution
|
||||
' monitord --> rocdc : POST /????? (route that use the same \nmethods as /booking/ to create NS & SA)
|
||||
monitord --> rocdc : POST /admiralty/source
|
||||
monitord --> rocdc : GET /admiralty/kubeconfig/:execution_id
|
||||
rocdc -> monitord : base64 encoded edited kubeconfig with token (**how to make it secure** ???)
|
||||
monitord --> locdc : POST /admiralty/secret/:execution_id
|
||||
monitord --> locdc : POST /admiralty/target/:execution_id
|
||||
monitord --> locdc : GET /admiralty/nodes/:execution_id \n(if the node is up it means ALL GOOD)
|
||||
@enduml
|
||||
4
env.env
Normal file
4
env.env
Normal file
@@ -0,0 +1,4 @@
|
||||
KUBERNETES_SERVICE_HOST=192.168.47.20
|
||||
KUBE_CA="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTVlk3ZHZhNEdYTVdkMy9jMlhLN3JLYjlnWXgyNSthaEE0NmkyNVBkSFAKRktQL2UxSVMyWVF0dzNYZW1TTUQxaStZdzJSaVppNUQrSVZUamNtNHdhcnFvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWtlUVJpNFJiODduME5yRnZaWjZHClc2SU55NnN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnRXA5ck04WmdNclRZSHYxZjNzOW5DZXZZeWVVa3lZUk4KWjUzazdoaytJS1FDSVFDbk05TnVGKzlTakIzNDFacGZ5ays2NEpWdkpSM3BhcmVaejdMd2lhNm9kdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
KUBE_CERT="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJWUxWNkFPQkdrU1F3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekl6TVRFeU1ETTJNQjRYRFRJME1EZ3dPREV3TVRNMU5sb1hEVEkxTURndwpPREV3TVRNMU5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJGQ2Q1MFdPeWdlQ2syQzcKV2FrOWY4MVAvSkJieVRIajRWOXBsTEo0ck5HeHFtSjJOb2xROFYxdUx5RjBtOTQ2Nkc0RmRDQ2dqaXFVSk92Swp3NVRPNnd5alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCVFJkOFI5cXVWK2pjeUVmL0ovT1hQSzMyS09XekFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQTArbThqTDBJVldvUTZ0dnB4cFo4NVlMalF1SmpwdXM0aDdnSXRxS3NmUVVDSUI2M2ZNdzFBMm5OVWU1TgpIUGZOcEQwSEtwcVN0Wnk4djIyVzliYlJUNklZCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRc3hXWk9pbnIrcVp4TmFEQjVGMGsvTDF5cE01VHAxOFRaeU92ektJazQKRTFsZWVqUm9STW0zNmhPeVljbnN3d3JoNnhSUnBpMW5RdGhyMzg0S0Z6MlBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBYZkVmYXJsZm8zTWhIL3lmemx6Cnl0OWlqbHN3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUxJL2dNYnNMT3MvUUpJa3U2WHVpRVMwTEE2cEJHMXgKcnBlTnpGdlZOekZsQWlFQW1wdjBubjZqN3M0MVI0QzFNMEpSL0djNE53MHdldlFmZWdEVGF1R2p3cFk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
KUBE_DATA="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5ZS1BFb1dhd1NKUzJlRW5oWmlYMk5VZlY1ZlhKV2krSVNnV09TNFE5VTlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVUozblJZN0tCNEtUWUx0WnFUMS96VS84a0Z2Sk1lUGhYMm1Vc25pczBiR3FZblkyaVZEeApYVzR2SVhTYjNqcm9iZ1YwSUtDT0twUWs2OHJEbE03ckRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
|
||||
112
go.mod
112
go.mod
@@ -1,57 +1,115 @@
|
||||
module oc-datacenter
|
||||
|
||||
go 1.22.0
|
||||
go 1.24.2
|
||||
|
||||
toolchain go1.22.4
|
||||
toolchain go1.24.4
|
||||
|
||||
require (
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418
|
||||
github.com/beego/beego/v2 v2.3.1
|
||||
go.mongodb.org/mongo-driver v1.17.1
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250626142041-d58dc5602416
|
||||
github.com/beego/beego/v2 v2.3.8
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/minio/madmin-go/v4 v4.1.1
|
||||
github.com/minio/minio-go/v7 v7.0.94
|
||||
github.com/necmettindev/randomstring v0.1.0
|
||||
go.mongodb.org/mongo-driver v1.17.4
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.32.3
|
||||
k8s.io/apimachinery v0.32.3
|
||||
k8s.io/client-go v0.32.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/biter777/countries v1.7.5 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.1 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/goraz/onion v0.1.3 // indirect
|
||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nats-io/nats.go v1.37.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||
github.com/nats-io/nats.go v1.43.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.60.1 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/prometheus/prom2json v1.4.2 // indirect
|
||||
github.com/prometheus/prometheus v0.304.1 // indirect
|
||||
github.com/robfig/cron v1.2.0 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/rs/zerolog v1.34.0 // indirect
|
||||
github.com/safchain/ethtool v0.6.1 // indirect
|
||||
github.com/secure-io/sio-go v0.3.1 // indirect
|
||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 // indirect
|
||||
github.com/smartystreets/goconvey v1.7.2 // indirect
|
||||
github.com/tinylib/msgp v1.3.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
golang.org/x/crypto v0.28.0 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
||||
247
go.sum
247
go.sum
@@ -1,26 +1,56 @@
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418 h1:24nc5qA6AkV6pIbJJeRASeUZmWuGkl+FO/r2oXazJ8w=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06 h1:+RSv62uIC7wsmibsp1XTanQMNznNeOGgPpfhb6ZHT4c=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250626135921-34b7cdcf06b0 h1:FGWOxAAw3Zh19A2FUeAbttsfuFJ3JDli/un9iCu6uD8=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250626135921-34b7cdcf06b0/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250626142041-d58dc5602416 h1:C51EHyggOm2QZ7INqhKOiyapTIbtRi8y2eJjVXzdtnM=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250626142041-d58dc5602416/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/beego/beego/v2 v2.3.1 h1:7MUKMpJYzOXtCUsTEoXOxsDV/UcHw6CPbaWMlthVNsc=
|
||||
github.com/beego/beego/v2 v2.3.1/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4=
|
||||
github.com/beego/beego/v2 v2.3.8 h1:wplhB1pF4TxR+2SS4PUej8eDoH4xGfxuHfS7wAk9VBc=
|
||||
github.com/beego/beego/v2 v2.3.8/go.mod h1:8vl9+RrXqvodrl9C8yivX1e6le6deCK6RWeq8R7gTTg=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/biter777/countries v1.7.5 h1:MJ+n3+rSxWQdqVJU8eBy9RqcdH6ePPn4PJHocVWUa+Q=
|
||||
github.com/biter777/countries v1.7.5/go.mod h1:1HSpZ526mYqKJcpT5Ti1kcGQ0L0SrXWIaptUWjFfv2E=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/etcd-io/etcd v3.3.17+incompatible/go.mod h1:cdZ77EstHBwVtD6iTgzgvogwcjo9m4iOqoijouPJ4bs=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc=
|
||||
github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc=
|
||||
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/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
@@ -29,26 +59,59 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
|
||||
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.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/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/goraz/onion v0.1.3 h1:KhyvbDA2b70gcz/d5izfwTiOH8SmrvV43AsVzpng3n0=
|
||||
github.com/goraz/onion v0.1.3/go.mod h1:XEmz1XoBz+wxTgWB8NwuvRm4RAu3vKxvrmYtzK+XCuQ=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -57,53 +120,99 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
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/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-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.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/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/minio/madmin-go/v4 v4.1.1 h1:Y7JHamjTwnyvXO9aike5SC0c0sNsbs/NpG37c525oe4=
|
||||
github.com/minio/madmin-go/v4 v4.1.1/go.mod h1:16tMDVIHWcp1zrmL6XrgCwPlZC7kB3UNNs5GDNnjYLQ=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM=
|
||||
github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
|
||||
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
|
||||
github.com/nats-io/nats.go v1.43.0 h1:uRFZ2FEoRvP64+UUhaTokyS18XBCR/xM2vQZKO4i8ug=
|
||||
github.com/nats-io/nats.go v1.43.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
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/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/necmettindev/randomstring v0.1.0 h1:HeU/mfLCd/5E9At7xznbTeEw5YldGW92fvK8lWtvPwE=
|
||||
github.com/necmettindev/randomstring v0.1.0/go.mod h1:h2nX9Jl0TLImuMt++XfLStVr8N76BmmP5D5EhLq0KEQ=
|
||||
github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
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/prom2json v1.4.2 h1:PxCTM+Whqi/eykO1MKsEL0p/zMpxp9ybpsmdFamw6po=
|
||||
github.com/prometheus/prom2json v1.4.2/go.mod h1:zuvPm7u3epZSbXPWHny6G+o8ETgu6eAK3oPr6yFkRWE=
|
||||
github.com/prometheus/prometheus v0.304.1 h1:e4kpJMb2Vh/PcR6LInake+ofcvFYHT+bCfmBvOkaZbY=
|
||||
github.com/prometheus/prometheus v0.304.1/go.mod h1:ioGx2SGKTY+fLnJSQCdTHqARVldGNS8OlIe3kvp98so=
|
||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/safchain/ethtool v0.6.1 h1:mhRnXE1H8fV8TTXh/HdqE4tXtb57r//BQh5pPYMuM5k=
|
||||
github.com/safchain/ethtool v0.6.1/go.mod h1:JzoNbG8xeg/BeVeVoMCtCb3UPWoppZZbFpA+1WFh+M0=
|
||||
github.com/secure-io/sio-go v0.3.1 h1:dNvY9awjabXTYGsTF1PiCySl9Ltofk9GA3VdWlo7rRc=
|
||||
github.com/secure-io/sio-go v0.3.1/go.mod h1:+xbkjDzPjwh4Axd07pRKSNriS9SCiYksWnZqdnfpQxs=
|
||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 h1:v9ezJDHA1XGxViAUSIoO/Id7Fl63u6d0YmsAm+/p2hs=
|
||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02/go.mod h1:RF16/A3L0xSa0oSERcnhd8Pu3IXSDZSK2gmGIMsttFE=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/skarademir/naturalsort v0.0.0-20150715044055-69a5d87bef62/go.mod h1:oIdVclZaltY1Nf7OQUkg1/2jImBJ+ZfKZuDIRSwk3p0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
@@ -111,10 +220,20 @@ github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYl
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
||||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
@@ -123,57 +242,115 @@ github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||
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=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.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.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=
|
||||
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k=
|
||||
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
||||
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
|
||||
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
||||
47
infrastructure/interface.go
Normal file
47
infrastructure/interface.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"oc-datacenter/conf"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type Infrastructure interface {
|
||||
CreateNamespace(ctx context.Context, ns string) error
|
||||
DeleteNamespace(ctx context.Context, ns string) error
|
||||
GenerateToken(ctx context.Context, ns string, duration int) (string, error)
|
||||
CreateServiceAccount(ctx context.Context, ns string) error
|
||||
CreateRoleBinding(ctx context.Context, ns string, roleBinding string, role string) error
|
||||
CreateRole(ctx context.Context, ns string, role string, groups [][]string, resources [][]string, verbs [][]string) error
|
||||
GetTargets(ctx context.Context) ([]string, error)
|
||||
CreateAdmiraltySource(context context.Context, executionId string) ([]byte, error)
|
||||
CreateKubeconfigSecret(context context.Context, kubeconfig string, executionId string, peerId string) ([]byte, error)
|
||||
GetKubeconfigSecret(context context.Context, executionId string, peerId string) ([]byte, error)
|
||||
CreateAdmiraltyTarget(context context.Context, executionId string, peerId string) ([]byte, error)
|
||||
GetOneNode(context context.Context, executionID string, peerId string) (*v1.Node, error)
|
||||
GetNamespace(context context.Context, executionID string) (*v1.Namespace, error)
|
||||
CreateSecret(context context.Context, minioId string, executionID string, access string, secret string) error
|
||||
CheckHealth() error
|
||||
}
|
||||
|
||||
var _service = map[string]func() (Infrastructure, error){
|
||||
"kubernetes": NewKubernetesService,
|
||||
}
|
||||
|
||||
func NewServiceByType(t string) (Infrastructure, error) {
|
||||
service, ok := _service[t]
|
||||
if !ok {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
return service()
|
||||
}
|
||||
|
||||
func NewService() (Infrastructure, error) {
|
||||
service, ok := _service[conf.GetConfig().Mode]
|
||||
if !ok {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
return service()
|
||||
}
|
||||
619
infrastructure/kubernetes.go
Normal file
619
infrastructure/kubernetes.go
Normal file
@@ -0,0 +1,619 @@
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"oc-datacenter/conf"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
authv1 "k8s.io/api/authentication/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
apply "k8s.io/client-go/applyconfigurations/core/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
var gvrSources = schema.GroupVersionResource{Group: "multicluster.admiralty.io", Version: "v1alpha1", Resource: "sources"}
|
||||
var gvrTargets = schema.GroupVersionResource{Group: "multicluster.admiralty.io", Version: "v1alpha1", Resource: "targets"}
|
||||
|
||||
|
||||
type KubernetesService struct {
|
||||
Set *kubernetes.Clientset
|
||||
}
|
||||
|
||||
func NewDynamicClient() (*dynamic.DynamicClient, error) {
|
||||
config := &rest.Config{
|
||||
Host: conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort,
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
CAData: []byte(conf.GetConfig().KubeCA),
|
||||
CertData: []byte(conf.GetConfig().KubeCert),
|
||||
KeyData: []byte(conf.GetConfig().KubeData),
|
||||
},
|
||||
}
|
||||
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error creating Dynamic client: " + err.Error())
|
||||
}
|
||||
if dynamicClient == nil {
|
||||
return nil, errors.New("Error creating Dynamic client: dynamicClient is nil")
|
||||
}
|
||||
|
||||
return dynamicClient, nil
|
||||
}
|
||||
|
||||
func NewKubernetesService() (Infrastructure, error) {
|
||||
config := &rest.Config{
|
||||
Host: conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort,
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
CAData: []byte(conf.GetConfig().KubeCA),
|
||||
CertData: []byte(conf.GetConfig().KubeCert),
|
||||
KeyData: []byte(conf.GetConfig().KubeData),
|
||||
},
|
||||
}
|
||||
|
||||
// Create clientset
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
fmt.Println("NewForConfig", clientset, err)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error creating Kubernetes client: " + err.Error())
|
||||
}
|
||||
if clientset == nil {
|
||||
return nil, errors.New("Error creating Kubernetes client: clientset is nil")
|
||||
}
|
||||
|
||||
return &KubernetesService{
|
||||
Set: clientset,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewRemoteKubernetesService(url string, ca string, cert string, key string) (Infrastructure, error) {
|
||||
decodedCa, _ := base64.StdEncoding.DecodeString(ca)
|
||||
decodedCert, _ := base64.StdEncoding.DecodeString(cert)
|
||||
decodedKey, _ := base64.StdEncoding.DecodeString(key)
|
||||
|
||||
config := &rest.Config{
|
||||
Host: url + ":6443",
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
CAData: decodedCa,
|
||||
CertData: decodedCert,
|
||||
KeyData: decodedKey,
|
||||
},
|
||||
}
|
||||
// Create clientset
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
fmt.Println("NewForConfig", clientset, err)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error creating Kubernetes client: " + err.Error())
|
||||
}
|
||||
if clientset == nil {
|
||||
return nil, errors.New("Error creating Kubernetes client: clientset is nil")
|
||||
}
|
||||
|
||||
return &KubernetesService{
|
||||
Set: clientset,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) CreateNamespace(ctx context.Context, ns string) error {
|
||||
// Define the namespace
|
||||
fmt.Println("ExecutionID in CreateNamespace() : ", ns)
|
||||
namespace := &v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ns,
|
||||
Labels: map[string]string{
|
||||
"multicluster-scheduler": "enabled",
|
||||
},
|
||||
},
|
||||
}
|
||||
// Create the namespace
|
||||
fmt.Println("Creating namespace...", k.Set)
|
||||
if _, err := k.Set.CoreV1().Namespaces().Create(ctx, namespace, metav1.CreateOptions{}); err != nil {
|
||||
return errors.New("Error creating namespace: " + err.Error())
|
||||
}
|
||||
fmt.Println("Namespace created successfully!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) CreateServiceAccount(ctx context.Context, ns string) error {
|
||||
// Create the ServiceAccount object
|
||||
serviceAccount := &v1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "sa-" + ns,
|
||||
Namespace: ns,
|
||||
},
|
||||
}
|
||||
// Create the ServiceAccount in the specified namespace
|
||||
_, err := k.Set.CoreV1().ServiceAccounts(ns).Create(ctx, serviceAccount, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return errors.New("Failed to create ServiceAccount: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) CreateRole(ctx context.Context, ns string, role string, groups [][]string, resources [][]string, verbs [][]string) error {
|
||||
// Create the Role object
|
||||
if len(groups) != len(resources) || len(resources) != len(verbs) {
|
||||
return errors.New("Invalid input: groups, resources, and verbs must have the same length")
|
||||
}
|
||||
rules := []rbacv1.PolicyRule{}
|
||||
for i, group := range groups {
|
||||
rules = append(rules, rbacv1.PolicyRule{
|
||||
APIGroups: group,
|
||||
Resources: resources[i],
|
||||
Verbs: verbs[i],
|
||||
})
|
||||
}
|
||||
r := &rbacv1.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: role,
|
||||
Namespace: ns,
|
||||
},
|
||||
Rules: rules,
|
||||
}
|
||||
// Create the Role in the specified namespace
|
||||
_, err := k.Set.RbacV1().Roles(ns).Create(ctx, r, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return errors.New("Failed to create Role: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) CreateRoleBinding(ctx context.Context, ns string, roleBinding string, role string) error {
|
||||
// Create the RoleBinding object
|
||||
rb := &rbacv1.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: roleBinding,
|
||||
Namespace: ns,
|
||||
},
|
||||
Subjects: []rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa-" + ns,
|
||||
Namespace: ns,
|
||||
},
|
||||
},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: role,
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
},
|
||||
}
|
||||
// Create the RoleBinding in the specified namespace
|
||||
_, err := k.Set.RbacV1().RoleBindings(ns).Create(ctx, rb, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return errors.New("Failed to create RoleBinding: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) DeleteNamespace(ctx context.Context, ns string) error {
|
||||
targetGVR := schema.GroupVersionResource{
|
||||
Group: "multicluster.admiralty.io",
|
||||
Version: "v1alpha1",
|
||||
Resource: "targets",
|
||||
}
|
||||
|
||||
// Delete the Target
|
||||
dyn, err := NewDynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dyn.Resource(targetGVR).Namespace(ns).Delete(context.TODO(), "target-"+ns, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = k.Set.CoreV1().ServiceAccounts(ns).Delete(context.TODO(), "sa-"+ns, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete the namespace
|
||||
if err := k.Set.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}); err != nil {
|
||||
return errors.New("Error deleting namespace: " + err.Error())
|
||||
}
|
||||
LockKill.Lock()
|
||||
Kill = append(Kill, ns)
|
||||
LockKill.Unlock()
|
||||
fmt.Println("Namespace deleted successfully!")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the string representing the token generated for the serviceAccount
|
||||
// in the namespace identified by the value `ns` with the name sa-`ns`, which is valid for
|
||||
// `duration` seconds
|
||||
func (k *KubernetesService) GenerateToken(ctx context.Context, ns string, duration int) (string, error) {
|
||||
// Define TokenRequest (valid for 1 hour)
|
||||
d := int64(duration)
|
||||
tokenRequest := &authv1.TokenRequest{
|
||||
Spec: authv1.TokenRequestSpec{
|
||||
ExpirationSeconds: &d, // 1 hour validity
|
||||
},
|
||||
}
|
||||
// Generate the token
|
||||
token, err := k.Set.CoreV1().
|
||||
ServiceAccounts(ns).
|
||||
CreateToken(ctx, "sa-"+ns, tokenRequest, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return "", errors.New("Failed to create token for ServiceAccount: " + err.Error())
|
||||
}
|
||||
return token.Status.Token, nil
|
||||
}
|
||||
|
||||
// Needs refactoring :
|
||||
// - Retrieving the metada (in a method that Unmarshall the part of the json in a metadata object)
|
||||
func (k *KubernetesService) GetTargets(ctx context.Context) ([]string, error) {
|
||||
|
||||
var listTargets []string
|
||||
resp, err := getCDRapiKube(*k.Set, ctx, "/apis/multicluster.admiralty.io/v1alpha1/targets")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println(string(resp))
|
||||
var targetDict map[string]interface{}
|
||||
err = json.Unmarshal(resp, &targetDict)
|
||||
if err != nil {
|
||||
fmt.Println("TODO: handle the error when unmarshalling k8s API response")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b, _ := json.MarshalIndent(targetDict, "", " ")
|
||||
fmt.Println(string(b))
|
||||
|
||||
data := targetDict["items"].([]interface{})
|
||||
|
||||
for _, item := range data {
|
||||
var metadata metav1.ObjectMeta
|
||||
item := item.(map[string]interface{})
|
||||
byteMetada, err := json.Marshal(item["metadata"])
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error while Marshalling metadata field")
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(byteMetada, &metadata)
|
||||
if err != nil {
|
||||
fmt.Println("Error while Unmarshalling metadata field to the library object")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listTargets = append(listTargets, metadata.Name)
|
||||
}
|
||||
|
||||
return listTargets, nil
|
||||
|
||||
}
|
||||
|
||||
// Admiralty Target allows a cluster to deploy pods to remote cluster
|
||||
//
|
||||
// The remote cluster must :
|
||||
//
|
||||
// - have declared a Source resource
|
||||
//
|
||||
// - have declared the same namespace as the one where the pods are created in the local cluster
|
||||
//
|
||||
// - have delcared a serviceAccount with sufficient permission to create pods
|
||||
func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context, executionId string, peerId string) ([]byte, error) {
|
||||
exists, err := k.GetKubeconfigSecret(context, executionId, peerId)
|
||||
if err != nil {
|
||||
fmt.Println("Error verifying kube-secret before creating target")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists == nil {
|
||||
fmt.Println("Target needs to be binded to a secret in namespace ", executionId)
|
||||
return nil, nil // Maybe we could create a wrapper for errors and add more info to have
|
||||
}
|
||||
|
||||
targetName := "target-" + getConcatenatedName(peerId, executionId)
|
||||
target := map[string]interface{}{
|
||||
"apiVersion": "multicluster.admiralty.io/v1alpha1",
|
||||
"kind": "Target",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": targetName,
|
||||
"namespace": executionId,
|
||||
"labels": map[string]interface{}{
|
||||
"peer": peerId,
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"kubeconfigSecret": map[string]string{
|
||||
"name": "kube-secret-" + getConcatenatedName(peerId, executionId),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res, err := dynamicClientApply(executionId, targetName, gvrTargets, context, target)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error when trying to apply Target definition :" + err.Error())
|
||||
}
|
||||
|
||||
return res, nil
|
||||
|
||||
}
|
||||
|
||||
// Admiralty Source allows a cluster to receive pods from a remote cluster
|
||||
//
|
||||
// The source must be associated to a serviceAccount, which will execute the pods locally.
|
||||
// This serviceAccount must have sufficient permission to create and patch pods
|
||||
//
|
||||
// This method is temporary to implement the use of Admiralty, but must be edited
|
||||
// to rather contact the oc-datacenter from the remote cluster to create the source
|
||||
// locally and retrieve the token for the serviceAccount
|
||||
func (k *KubernetesService) CreateAdmiraltySource(context context.Context, executionId string) ([]byte, error) {
|
||||
|
||||
source := map[string]interface{}{
|
||||
"apiVersion": "multicluster.admiralty.io/v1alpha1",
|
||||
"kind": "Source",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "source-" + executionId,
|
||||
"namespace": executionId,
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"serviceAccountName": "sa-" + executionId,
|
||||
},
|
||||
}
|
||||
|
||||
res, err := dynamicClientApply(executionId, "source-"+executionId, gvrSources, context, source)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error when trying to apply Source definition :" + err.Error())
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Create a secret from a kubeconfing. Use it to create the secret binded to an Admiralty
|
||||
// target, which must contain the serviceAccount's token value
|
||||
func (k *KubernetesService) CreateKubeconfigSecret(context context.Context, kubeconfig string, executionId string, peerId string) ([]byte, error) {
|
||||
config, err := base64.StdEncoding.DecodeString(kubeconfig)
|
||||
// config, err := base64.RawStdEncoding.DecodeString(kubeconfig)
|
||||
if err != nil {
|
||||
fmt.Println("Error while encoding kubeconfig")
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secretApplyConfig := apply.Secret("kube-secret-"+getConcatenatedName(peerId, executionId),
|
||||
executionId).
|
||||
WithData(map[string][]byte{
|
||||
"config": config,
|
||||
},
|
||||
)
|
||||
|
||||
// exists, err := k.GetKubeconfigSecret(context,executionId)
|
||||
// if err != nil {
|
||||
// fmt.Println("Error verifying if kube secret exists in namespace ", executionId)
|
||||
// return nil, err
|
||||
// }
|
||||
// if exists != nil {
|
||||
// fmt.Println("kube-secret already exists in namespace", executionId)
|
||||
// fmt.Println("Overriding existing kube-secret with a newer resource")
|
||||
// // TODO : implement DeleteKubeConfigSecret(executionID)
|
||||
// deleted, err := k.DeleteKubeConfigSecret(executionId)
|
||||
// _ = deleted
|
||||
// _ = err
|
||||
// }
|
||||
|
||||
resp, err := k.Set.CoreV1().
|
||||
Secrets(executionId).
|
||||
Apply(context,
|
||||
secretApplyConfig,
|
||||
metav1.ApplyOptions{
|
||||
FieldManager: "admiralty-manager",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error while trying to contact API to get secret kube-secret-" + executionId)
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't marshal resp from : ", data)
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) GetKubeconfigSecret(context context.Context, executionId string, peerId string) ([]byte, error) {
|
||||
resp, err := k.Set.CoreV1().
|
||||
Secrets(executionId).
|
||||
Get(context, "kube-secret-"+getConcatenatedName(peerId, executionId), metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
fmt.Println("kube-secret not found for execution", executionId)
|
||||
return nil, nil
|
||||
}
|
||||
fmt.Println("Error while trying to contact API to get secret kube-secret-" + executionId)
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(resp)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't marshal resp from : ", data)
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) DeleteKubeConfigSecret(executionID string) ([]byte, error) {
|
||||
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) GetNamespace(context context.Context, executionID string)(*v1.Namespace,error){
|
||||
resp, err := k.Set.CoreV1().Namespaces().Get(context,executionID,metav1.GetOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
logger := oclib.GetLogger()
|
||||
logger.Error().Msg("An error occured when trying to get namespace " + executionID + " : " + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
||||
func getCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string) ([]byte, error) {
|
||||
resp, err := client.RESTClient().Get().
|
||||
AbsPath(path).
|
||||
DoRaw(ctx) // from https://stackoverflow.com/questions/60764908/how-to-access-kubernetes-crd-using-client-go
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error from k8s API when getting "+path+" : ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func dynamicClientApply(executionId string, resourceName string, resourceDefinition schema.GroupVersionResource, ctx context.Context, object map[string]interface{}) ([]byte, error) {
|
||||
cli, err := NewDynamicClient()
|
||||
if err != nil {
|
||||
return nil, errors.New("Could not retrieve dynamic client when creating Admiralty Source : " + err.Error())
|
||||
}
|
||||
|
||||
res, err := cli.Resource(resourceDefinition).
|
||||
Namespace(executionId).
|
||||
Apply(ctx,
|
||||
resourceName,
|
||||
&unstructured.Unstructured{Object: object},
|
||||
metav1.ApplyOptions{
|
||||
FieldManager: "kubectl-client-side-apply",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
o, err := json.Marshal(object)
|
||||
fmt.Println("Error from k8s API when applying "+fmt.Sprint(string(o))+" to "+gvrSources.String()+" : ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We can add more info to the log with the content of resp if not nil
|
||||
resByte, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
// fmt.Println("Error trying to create a Source on remote cluster : ", err , " : ", res)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resByte, nil
|
||||
|
||||
}
|
||||
|
||||
func (k *KubernetesService) CheckHealth() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Check API server connectivity
|
||||
_, err := k.Set.ServerVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("API server unreachable: %v", err)
|
||||
}
|
||||
|
||||
// Check nodes status
|
||||
nodes, err := k.Set.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list nodes: %v", err)
|
||||
}
|
||||
for _, node := range nodes.Items {
|
||||
for _, condition := range node.Status.Conditions {
|
||||
if condition.Type == "Ready" && condition.Status != "True" {
|
||||
return fmt.Errorf("node %s not ready", node.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Check if all pods in kube-system are running
|
||||
pods, err := k.Set.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list pods: %v", err)
|
||||
}
|
||||
for _, pod := range pods.Items {
|
||||
if pod.Status.Phase != "Running" && pod.Status.Phase != "Succeeded" {
|
||||
return fmt.Errorf("pod %s in namespace kube-system is %s", pod.Name, pod.Status.Phase)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the Kubernetes' Node object corresponding to the executionID if it exists on this host
|
||||
//
|
||||
// The node is created when an admiralty Target (on host) can connect to an admiralty Source (on remote)
|
||||
func (k *KubernetesService) GetOneNode(context context.Context, executionID string, peerId string) (*v1.Node, error) {
|
||||
concatenatedName := getConcatenatedName(peerId, executionID)
|
||||
|
||||
res, err := k.Set.CoreV1().
|
||||
Nodes().
|
||||
List(
|
||||
context,
|
||||
metav1.ListOptions{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("Error getting the list of nodes from k8s API")
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, node := range res.Items {
|
||||
if isNode := strings.Contains(node.Name, "admiralty-"+executionID+"-target-"+concatenatedName+"-"); isNode {
|
||||
return &node, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesService) CreateSecret(context context.Context, minioId string, executionID string, access string, secret string) error {
|
||||
|
||||
data := map[string][]byte{
|
||||
"access-key": []byte(access),
|
||||
"secret-key": []byte(secret),
|
||||
}
|
||||
|
||||
s := v1.Secret{
|
||||
Type: v1.SecretTypeOpaque,
|
||||
Data: data,
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: minioId+"-secret-s3",
|
||||
},
|
||||
}
|
||||
|
||||
_, err := k.Set.CoreV1().Secrets(executionID).Create(context,&s,metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
logger := oclib.GetLogger()
|
||||
logger.Error().Msg("An error happened when creating the secret holding minio credentials in namespace " + executionID + " : " + err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a concatenation of the peerId and namespace in order for
|
||||
// kubernetes ressources to have a unique name, under 63 characters
|
||||
// and yet identify which peer they are created for
|
||||
func getConcatenatedName(peerId string, namespace string) string {
|
||||
s := strings.Split(namespace, "-")[:2]
|
||||
n := s[0] + "-" + s[1]
|
||||
|
||||
return peerId + "-" + n
|
||||
}
|
||||
106
infrastructure/minio.go
Normal file
106
infrastructure/minio.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"oc-datacenter/conf"
|
||||
|
||||
"github.com/minio/madmin-go/v4"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
|
||||
"github.com/necmettindev/randomstring"
|
||||
)
|
||||
|
||||
type MinioService struct{
|
||||
Url string
|
||||
RootKey string
|
||||
RootSecret string
|
||||
MinioClient *madmin.AdminClient
|
||||
}
|
||||
|
||||
type StatementEntry struct {
|
||||
Effect string `json:"Effect"`
|
||||
Action []string `json:"Action"`
|
||||
Resource string `json:"Resource"`
|
||||
}
|
||||
|
||||
type PolicyDocument struct {
|
||||
Version string `json:"Version"`
|
||||
Statement []StatementEntry `json:"Statement"`
|
||||
}
|
||||
|
||||
|
||||
func NewMinioService(url string) *MinioService {
|
||||
return &MinioService{
|
||||
Url: url,
|
||||
RootKey: conf.GetConfig().MinioRootKey,
|
||||
RootSecret: conf.GetConfig().MinioRootSecret,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MinioService) CreateClient() error {
|
||||
cred := credentials.NewStaticV4(m.RootKey,m.RootSecret,"")
|
||||
cli, err := madmin.NewWithOptions(m.Url, &madmin.Options{Creds: cred, Secure: false}) // Maybe in the future we should use the secure option ?
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.MinioClient = cli
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MinioService) CreateCredentials(executionId string) (string,string,error){
|
||||
|
||||
policy := PolicyDocument{
|
||||
Version: "2012-10-17",
|
||||
Statement: []StatementEntry{
|
||||
{
|
||||
Effect: "Allow",
|
||||
Action: []string{"s3:GetObject", "s3:PutObject"},
|
||||
Resource: "arn:aws:s3:::"+executionId+"/*",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
return "","",err
|
||||
}
|
||||
|
||||
randAccess, randSecret := getRandomCreds()
|
||||
|
||||
req := madmin.AddServiceAccountReq{
|
||||
Policy: p,
|
||||
TargetUser: m.RootKey,
|
||||
AccessKey: randAccess,
|
||||
SecretKey: randSecret,
|
||||
}
|
||||
|
||||
res, err := m.MinioClient.AddServiceAccount(context.Background(), req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
|
||||
return res.AccessKey, res.SecretKey, nil
|
||||
|
||||
}
|
||||
|
||||
func getRandomCreds() (string, string){
|
||||
opts := randomstring.GenerationOptions{
|
||||
Length: 20,
|
||||
}
|
||||
|
||||
a, _ := randomstring.GenerateString(opts)
|
||||
|
||||
opts.Length = 40
|
||||
s, _ := randomstring.GenerateString(opts)
|
||||
|
||||
return a,s
|
||||
|
||||
}
|
||||
|
||||
func (m *MinioService) CreateBucket(executionId string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
203
infrastructure/prometheus.go
Normal file
203
infrastructure/prometheus.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"cloud.o-forge.io/core/oc-lib/models/common/models"
|
||||
"cloud.o-forge.io/core/oc-lib/models/live"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type MetricsSnapshot struct {
|
||||
From string `json:"origin"`
|
||||
Metrics []Metric `json:"metrics"`
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
Name string `json:"name"`
|
||||
Value float64 `json:"value"`
|
||||
Error error `json:"error"`
|
||||
}
|
||||
|
||||
type PrometheusResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data struct {
|
||||
ResultType string `json:"resultType"`
|
||||
Result []struct {
|
||||
Metric map[string]string `json:"metric"`
|
||||
Value []interface{} `json:"value"` // [timestamp, value]
|
||||
} `json:"result"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
var queriesMetrics = []string{
|
||||
"rate(container_cpu_usage_seconds_total{namespace=\"%s\"}[1m]) * 100",
|
||||
"container_memory_usage_bytes{namespace=\"%s\"}",
|
||||
"(container_fs_usage_bytes{namespace=\"%s\"}) / (container_fs_limit_bytes{namespace=\"%s\"}) * 100",
|
||||
"DCGM_FI_DEV_GPU_UTIL{namespace=\"%s\"}",
|
||||
// "system_load_average",
|
||||
"rate(container_fs_reads_bytes_total{namespace=\"%s\"}[1m])",
|
||||
"rate(container_fs_writes_bytes_total{namespace=\"%s\"}[1m])",
|
||||
"rate(container_network_receive_bytes_total{namespace=\"%s\"}[1m])",
|
||||
"rate(container_network_transmit_bytes_total{namespace=\"%s\"}[1m])",
|
||||
// "system_network_latency_ms",
|
||||
"rate(http_requests_total{namespace=\"%s\"}[1m])",
|
||||
"(rate(http_requests_total{status=~\"5..\", namespace=\"%s\"}[1m]) / rate(http_requests_total{namespace=\"%s\"}[1m])) * 100",
|
||||
// "app_mean_time_to_repair_seconds",
|
||||
// "app_mean_time_between_failure_seconds",
|
||||
}
|
||||
|
||||
type PrometheusService struct {
|
||||
}
|
||||
|
||||
func NewPrometheusService() *PrometheusService {
|
||||
return &PrometheusService{}
|
||||
}
|
||||
|
||||
func (p *PrometheusService) queryPrometheus(promURL string, expr string, namespace string) models.Metric {
|
||||
metric := models.Metric{Name: expr, Value: -1}
|
||||
resp, err := http.Get(promURL + "/api/v1/query?query=" + url.QueryEscape(fmt.Sprintf(expr, namespace)))
|
||||
if err != nil {
|
||||
metric.Error = err
|
||||
} else {
|
||||
defer resp.Body.Close()
|
||||
if body, err := io.ReadAll(resp.Body); err == nil {
|
||||
var result PrometheusResponse
|
||||
if err = json.Unmarshal(body, &result); err == nil && len(result.Data.Result) > 0 && len(result.Data.Result[0].Value) == 2 {
|
||||
metric.Value, metric.Error = strconv.ParseFloat(fmt.Sprintf("%s", result.Data.Result[0].Value[1]), 64)
|
||||
}
|
||||
}
|
||||
}
|
||||
return metric
|
||||
}
|
||||
|
||||
func (p *PrometheusService) Call(book *booking.Booking, user string, peerID string, groups []string) (*booking.Booking, map[string]models.MetricsSnapshot) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
metrics := map[string]models.MetricsSnapshot{}
|
||||
// get all booking... from executions_id == namespace typed datacenter.
|
||||
|
||||
cUAccess := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_DATACENTER), user, peerID, groups, nil)
|
||||
cRAccess := oclib.NewRequest(oclib.LibDataEnum(oclib.COMPUTE_RESOURCE), user, peerID, groups, nil)
|
||||
|
||||
rr := cRAccess.LoadOne(book.ResourceID)
|
||||
if rr.Err != "" {
|
||||
fmt.Errorf("can't proceed because of unfound resource %s : %s", book.ResourceID, rr.Err)
|
||||
return book, metrics
|
||||
}
|
||||
computeRes := rr.ToComputeResource()
|
||||
for _, instance := range computeRes.Instances {
|
||||
res := cUAccess.Search(&dbs.Filters{
|
||||
And: map[string][]dbs.Filter{
|
||||
"source": {{Operator: dbs.EQUAL.String(), Value: instance.Source}},
|
||||
"abstractlive.resources_id": {{Operator: dbs.EQUAL.String(), Value: computeRes.GetID()}},
|
||||
},
|
||||
}, "", false)
|
||||
if res.Err != "" {
|
||||
continue
|
||||
}
|
||||
for _, r := range res.Data {
|
||||
// TODO watch out ... to not exec on an absent datacenter...
|
||||
if r.(*live.LiveDatacenter).MonitorPath == "" {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
snapshot := models.MetricsSnapshot{From: instance.Source, Metrics: []models.Metric{}}
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for _, expr := range queriesMetrics {
|
||||
snapshot.Metrics = append(snapshot.Metrics,
|
||||
p.queryPrometheus(r.(*live.LiveDatacenter).MonitorPath, expr, book.ExecutionsID))
|
||||
}
|
||||
metrics[instance.Name] = snapshot
|
||||
}()
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
return book, metrics
|
||||
}
|
||||
|
||||
var LockKill = &sync.Mutex{}
|
||||
|
||||
// TODO kill procedure
|
||||
func (p *PrometheusService) Stream(bookingID string, interval time.Duration, user string, peerID string, groups []string, websocket *websocket.Conn) {
|
||||
|
||||
max := 100
|
||||
bookIDS := []string{}
|
||||
mets := map[string][]models.MetricsSnapshot{}
|
||||
bAccess := oclib.NewRequest(oclib.LibDataEnum(oclib.BOOKING), user, peerID, groups, nil)
|
||||
book := bAccess.LoadOne(bookingID)
|
||||
if book.Err != "" {
|
||||
fmt.Errorf("stop because of empty : %s", book.Err)
|
||||
}
|
||||
f := func(e *booking.Booking) bool {
|
||||
if e.ExpectedEndDate == nil {
|
||||
return true
|
||||
}
|
||||
return time.Now().Before(*e.ExpectedEndDate)
|
||||
}
|
||||
for f(book.Data.(*booking.Booking)) {
|
||||
if slices.Contains(Kill, book.Data.(*booking.Booking).ExecutionsID) {
|
||||
newKill := []string{}
|
||||
for _, k := range Kill {
|
||||
if k != book.Data.(*booking.Booking).ExecutionsID {
|
||||
newKill = append(newKill, k)
|
||||
}
|
||||
}
|
||||
LockKill.Lock()
|
||||
Kill = newKill
|
||||
LockKill.Unlock()
|
||||
break
|
||||
}
|
||||
|
||||
go func() {
|
||||
book, metrics := p.Call(book.Data.(*booking.Booking), user, peerID, groups)
|
||||
for k, v := range metrics {
|
||||
if me, ok := mets[k]; !ok {
|
||||
mets[k] = []models.MetricsSnapshot{v}
|
||||
} else {
|
||||
me = append(me, v)
|
||||
mets[k] = me
|
||||
}
|
||||
}
|
||||
bookIDS = append(bookIDS, bookingID)
|
||||
if websocket != nil {
|
||||
(*websocket).WriteJSON(metrics)
|
||||
}
|
||||
if len(bookIDS) != max {
|
||||
return
|
||||
}
|
||||
if book.ExecutionMetrics == nil {
|
||||
book.ExecutionMetrics = mets
|
||||
} else {
|
||||
for kk, vv := range mets {
|
||||
if em, ok := book.ExecutionMetrics[kk]; !ok {
|
||||
book.ExecutionMetrics[kk] = vv
|
||||
} else {
|
||||
em = append(em, vv...)
|
||||
book.ExecutionMetrics[kk] = em
|
||||
}
|
||||
}
|
||||
}
|
||||
book.GetAccessor(nil).UpdateOne(book, bookingID)
|
||||
bookIDS = []string{}
|
||||
|
||||
}()
|
||||
time.Sleep(interval)
|
||||
}
|
||||
}
|
||||
|
||||
var Kill = []string{}
|
||||
|
||||
// should add a datacenter... under juridiction... of opencloud...
|
||||
23
main.go
23
main.go
@@ -1,7 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"oc-datacenter/conf"
|
||||
_ "oc-datacenter/routers"
|
||||
"os"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
@@ -17,6 +20,26 @@ func main() {
|
||||
|
||||
// Load the right config file
|
||||
o := oclib.GetConfLoader()
|
||||
conf.GetConfig().Mode = o.GetStringDefault("MODE", "kubernetes")
|
||||
conf.GetConfig().KubeHost = o.GetStringDefault("KUBERNETES_SERVICE_HOST", os.Getenv("KUBERNETES_SERVICE_HOST"))
|
||||
conf.GetConfig().KubePort = o.GetStringDefault("KUBERNETES_SERVICE_PORT", "6443")
|
||||
|
||||
sDec, err := base64.StdEncoding.DecodeString(o.GetStringDefault("KUBE_CA", ""))
|
||||
if err == nil {
|
||||
conf.GetConfig().KubeCA = string(sDec)
|
||||
}
|
||||
sDec, err = base64.StdEncoding.DecodeString(o.GetStringDefault("KUBE_CERT", ""))
|
||||
if err == nil {
|
||||
conf.GetConfig().KubeCert = string(sDec)
|
||||
}
|
||||
sDec, err = base64.StdEncoding.DecodeString(o.GetStringDefault("KUBE_DATA", ""))
|
||||
if err == nil {
|
||||
conf.GetConfig().KubeData = string(sDec)
|
||||
}
|
||||
|
||||
conf.GetConfig().MinioRootKey = o.GetStringDefault("MINIO_ADMIN_ACCESS","")
|
||||
conf.GetConfig().MinioRootSecret = o.GetStringDefault("MINIO_ADMIN_SECRET","")
|
||||
|
||||
|
||||
// feed the library with the loaded config
|
||||
oclib.SetConfig(
|
||||
|
||||
56
models/kubeconfig.go
Normal file
56
models/kubeconfig.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package models
|
||||
|
||||
// KubeConfigValue is a struct used to create a kubectl configuration YAML file.
|
||||
type KubeConfigValue struct {
|
||||
APIVersion string `yaml:"apiVersion" json:"apiVersion"`
|
||||
Kind string `yaml:"kind" json:"kind"`
|
||||
Clusters []KubeconfigNamedCluster `yaml:"clusters" json:"clusters"`
|
||||
Users []KubeconfigUser `yaml:"users" json:"users"`
|
||||
Contexts []KubeconfigNamedContext `yaml:"contexts" json:"contexts"`
|
||||
CurrentContext string `yaml:"current-context" json:"current-context"`
|
||||
Preferences struct{} `yaml:"preferences" json:"preferences"`
|
||||
}
|
||||
|
||||
// KubeconfigUser is a struct used to create a kubectl configuration YAML file
|
||||
type KubeconfigUser struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
User KubeconfigUserKeyPair `yaml:"user" json:"user"`
|
||||
|
||||
}
|
||||
|
||||
// KubeconfigUserKeyPair is a struct used to create a kubectl configuration YAML file
|
||||
type KubeconfigUserKeyPair struct {
|
||||
Token string `yaml:"token" json:"token"`
|
||||
}
|
||||
|
||||
// KubeconfigAuthProvider is a struct used to create a kubectl authentication provider
|
||||
type KubeconfigAuthProvider struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Config map[string]string `yaml:"config" json:"config"`
|
||||
}
|
||||
|
||||
// KubeconfigNamedCluster is a struct used to create a kubectl configuration YAML file
|
||||
type KubeconfigNamedCluster struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Cluster KubeconfigCluster `yaml:"cluster" json:"cluster"`
|
||||
}
|
||||
|
||||
// KubeconfigCluster is a struct used to create a kubectl configuration YAML file
|
||||
type KubeconfigCluster struct {
|
||||
Server string `yaml:"server" json:"server"`
|
||||
CertificateAuthorityData string `yaml:"certificate-authority-data" json:"certificate-authority-data"`
|
||||
CertificateAuthority string `yaml:"certificate-authority" json:"certificate-authority"`
|
||||
}
|
||||
|
||||
// KubeconfigNamedContext is a struct used to create a kubectl configuration YAML file
|
||||
type KubeconfigNamedContext struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Context KubeconfigContext `yaml:"context" json:"context"`
|
||||
}
|
||||
|
||||
// KubeconfigContext is a struct used to create a kubectl configuration YAML file
|
||||
type KubeconfigContext struct {
|
||||
Cluster string `yaml:"cluster" json:"cluster"`
|
||||
Namespace string `yaml:"namespace,omitempty" json:"namespace,omitempty"`
|
||||
User string `yaml:"user" json:"user"`
|
||||
}
|
||||
BIN
oc-datacenter
Executable file
BIN
oc-datacenter
Executable file
Binary file not shown.
@@ -7,6 +7,87 @@ import (
|
||||
|
||||
func init() {
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetAdmiraltyKubeconfig",
|
||||
Router: `/kubeconfig/:execution`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetNodeReady",
|
||||
Router: `/node/:execution/:peer`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetKubeSecret",
|
||||
Router: `/secret/:execution/:peer`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "CreateKubeSecret",
|
||||
Router: `/secret/:execution/:peer`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "CreateAdmiraltySource",
|
||||
Router: `/source/:execution`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "CreateAdmiraltyTarget",
|
||||
Router: `/target/:execution/:peer`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetAllTargets",
|
||||
Router: `/targets`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetOneTarget",
|
||||
Router: `/targets/:execution`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
|
||||
beego.ControllerComments{
|
||||
Method: "DeleteAdmiraltySession",
|
||||
Router: `/targets/:execution`,
|
||||
AllowHTTPMethods: []string{"delete"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetAll",
|
||||
@@ -34,6 +115,24 @@ func init() {
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "Log",
|
||||
Router: `/:id`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "Put",
|
||||
Router: `/:id`,
|
||||
AllowHTTPMethods: []string{"put"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "Check",
|
||||
@@ -43,6 +142,24 @@ func init() {
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "ExtendForExecution",
|
||||
Router: `/extend/:resource_id/from_execution/:execution_id/to/:duration`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "ExtendForNamespace",
|
||||
Router: `/extend/:resource_id/from_namespace/:namespace/to/:duration`,
|
||||
AllowHTTPMethods: []string{"post"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "Search",
|
||||
@@ -52,6 +169,51 @@ func init() {
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "ExecutionSearch",
|
||||
Router: `/search/execution/:id`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:DatacenterController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:DatacenterController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetAll",
|
||||
Router: `/`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:DatacenterController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:DatacenterController"],
|
||||
beego.ControllerComments{
|
||||
Method: "Get",
|
||||
Router: `/:id`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:MinioController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:MinioController"],
|
||||
beego.ControllerComments{
|
||||
Method: "CreateServiceAccount",
|
||||
Router: `/serviceaccount/:minioId/:executions`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:SessionController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:SessionController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetToken",
|
||||
Router: `/token/:id/:duration`,
|
||||
AllowHTTPMethods: []string{"get"},
|
||||
MethodParams: param.Make(),
|
||||
Filters: nil,
|
||||
Params: nil})
|
||||
|
||||
beego.GlobalControllerRouter["oc-datacenter/controllers:VersionController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:VersionController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetAll",
|
||||
|
||||
@@ -15,6 +15,15 @@ import (
|
||||
|
||||
func init() {
|
||||
ns := beego.NewNamespace("/oc/",
|
||||
beego.NSInclude(
|
||||
&controllers.DatacenterController{},
|
||||
),
|
||||
|
||||
beego.NSNamespace("/session",
|
||||
beego.NSInclude(
|
||||
&controllers.SessionController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/booking",
|
||||
beego.NSInclude(
|
||||
&controllers.BookingController{},
|
||||
@@ -25,6 +34,16 @@ func init() {
|
||||
&controllers.VersionController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/admiralty",
|
||||
beego.NSInclude(
|
||||
&controllers.AdmiraltyController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/minio",
|
||||
beego.NSInclude(
|
||||
&controllers.MinioController{},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
beego.AddNamespace(ns)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 665 B |
Binary file not shown.
|
Before Width: | Height: | Size: 628 B |
@@ -1,60 +0,0 @@
|
||||
<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
// End Swagger UI call region
|
||||
|
||||
window.ui = ui;
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,79 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>Swagger UI: OAuth2 Redirect</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1);
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&");
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value);
|
||||
}
|
||||
) : {};
|
||||
|
||||
isValid = qp.state === sentState;
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorization_code"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg;
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
if (document.readyState !== 'loading') {
|
||||
run();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
run();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,196 +0,0 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "oc-datacenter",
|
||||
"description": "Monitor owned datacenter activity\n",
|
||||
"version": "1.0.0",
|
||||
"termsOfService": "http://cloud.o-forge.io/",
|
||||
"contact": {
|
||||
"email": "admin@o-cloud.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "AGPL",
|
||||
"url": "https://www.gnu.org/licenses/agpl-3.0.html"
|
||||
}
|
||||
},
|
||||
"basePath": "/oc/",
|
||||
"paths": {
|
||||
"/booking/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"booking"
|
||||
],
|
||||
"description": "find booking by id\n\u003cbr\u003e",
|
||||
"operationId": "BookingController.GetAll",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "{booking} models.booking"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"booking"
|
||||
],
|
||||
"description": "create booking\n\u003cbr\u003e",
|
||||
"operationId": "BookingController.Post",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "booking",
|
||||
"description": "the booking you want to post",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/booking/check/{id}/{start_date}/{end_date}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"booking"
|
||||
],
|
||||
"description": "check booking\n\u003cbr\u003e",
|
||||
"operationId": "BookingController.Check",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"description": "id of the datacenter",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "start_date",
|
||||
"description": "2006-01-02T15:04:05",
|
||||
"type": "string",
|
||||
"default": "the booking start date"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "end_date",
|
||||
"description": "2006-01-02T15:04:05",
|
||||
"type": "string",
|
||||
"default": "the booking end date"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/booking/search/{start_date}/{end_date}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"booking"
|
||||
],
|
||||
"description": "search bookings\n\u003cbr\u003e",
|
||||
"operationId": "BookingController.Search",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "start_date",
|
||||
"description": "the word search you want to get",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "end_date",
|
||||
"description": "the word search you want to get",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "{workspace} models.workspace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/booking/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"booking"
|
||||
],
|
||||
"description": "find booking by id\n\u003cbr\u003e",
|
||||
"operationId": "BookingController.Get",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "id",
|
||||
"description": "the id you want to get",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "{booking} models.booking"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/version/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"version"
|
||||
],
|
||||
"description": "get version\n\u003cbr\u003e",
|
||||
"operationId": "VersionController.GetAll",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/version/status": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"version"
|
||||
],
|
||||
"description": "get status\n\u003cbr\u003e",
|
||||
"operationId": "VersionController.Status",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"models.object": {
|
||||
"title": "object",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "booking",
|
||||
"description": "Operations about workspace\n"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"description": "VersionController operations for Version\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: oc-datacenter
|
||||
description: |
|
||||
Monitor owned datacenter activity
|
||||
version: 1.0.0
|
||||
termsOfService: http://cloud.o-forge.io/
|
||||
contact:
|
||||
email: admin@o-cloud.io
|
||||
license:
|
||||
name: AGPL
|
||||
url: https://www.gnu.org/licenses/agpl-3.0.html
|
||||
basePath: /oc/
|
||||
paths:
|
||||
/booking/:
|
||||
get:
|
||||
tags:
|
||||
- booking
|
||||
description: |-
|
||||
find booking by id
|
||||
<br>
|
||||
operationId: BookingController.GetAll
|
||||
responses:
|
||||
"200":
|
||||
description: '{booking} models.booking'
|
||||
post:
|
||||
tags:
|
||||
- booking
|
||||
description: |-
|
||||
create booking
|
||||
<br>
|
||||
operationId: BookingController.Post
|
||||
parameters:
|
||||
- in: body
|
||||
name: booking
|
||||
description: the booking you want to post
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
schema:
|
||||
$ref: '#/definitions/models.object'
|
||||
/booking/{id}:
|
||||
get:
|
||||
tags:
|
||||
- booking
|
||||
description: |-
|
||||
find booking by id
|
||||
<br>
|
||||
operationId: BookingController.Get
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
description: the id you want to get
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: '{booking} models.booking'
|
||||
/booking/check/{id}/{start_date}/{end_date}:
|
||||
get:
|
||||
tags:
|
||||
- booking
|
||||
description: |-
|
||||
check booking
|
||||
<br>
|
||||
operationId: BookingController.Check
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
description: id of the datacenter
|
||||
type: string
|
||||
- in: path
|
||||
name: start_date
|
||||
description: 2006-01-02T15:04:05
|
||||
type: string
|
||||
default: the booking start date
|
||||
- in: path
|
||||
name: end_date
|
||||
description: 2006-01-02T15:04:05
|
||||
type: string
|
||||
default: the booking end date
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
schema:
|
||||
$ref: '#/definitions/models.object'
|
||||
/booking/search/{start_date}/{end_date}:
|
||||
get:
|
||||
tags:
|
||||
- booking
|
||||
description: |-
|
||||
search bookings
|
||||
<br>
|
||||
operationId: BookingController.Search
|
||||
parameters:
|
||||
- in: path
|
||||
name: start_date
|
||||
description: the word search you want to get
|
||||
required: true
|
||||
type: string
|
||||
- in: path
|
||||
name: end_date
|
||||
description: the word search you want to get
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: '{workspace} models.workspace'
|
||||
/version/:
|
||||
get:
|
||||
tags:
|
||||
- version
|
||||
description: |-
|
||||
get version
|
||||
<br>
|
||||
operationId: VersionController.GetAll
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
/version/status:
|
||||
get:
|
||||
tags:
|
||||
- version
|
||||
description: |-
|
||||
get status
|
||||
<br>
|
||||
operationId: VersionController.Status
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
definitions:
|
||||
models.object:
|
||||
title: object
|
||||
type: object
|
||||
tags:
|
||||
- name: booking
|
||||
description: |
|
||||
Operations about workspace
|
||||
- name: version
|
||||
description: |
|
||||
VersionController operations for Version
|
||||
Reference in New Issue
Block a user