Compare commits
72 Commits
fd8e397e16
...
feature/mu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
8
Makefile
8
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
|
||||
|
||||
|
||||
53
README.md
53
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)
|
||||
|
||||
## 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
|
||||
|
||||
22
conf/config.go
Normal file
22
conf/config.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package conf
|
||||
|
||||
import "sync"
|
||||
|
||||
type Config struct {
|
||||
Mode string
|
||||
KubeHost string
|
||||
KubePort string
|
||||
KubeCA string
|
||||
KubeCert string
|
||||
KubeData string
|
||||
}
|
||||
|
||||
var instance *Config
|
||||
var once sync.Once
|
||||
|
||||
func GetConfig() *Config {
|
||||
once.Do(func() {
|
||||
instance = &Config{}
|
||||
})
|
||||
return instance
|
||||
}
|
||||
572
controllers/admiralty.go
Normal file
572
controllers/admiralty.go
Normal file
@@ -0,0 +1,572 @@
|
||||
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())
|
||||
id = "target-"+id
|
||||
found := slices.Contains(res,id)
|
||||
if !found {
|
||||
c.Ctx.Output.SetStatus(404)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
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,
|
||||
}
|
||||
|
||||
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{
|
||||
models.KubeconfigUser{
|
||||
Name: "default",
|
||||
User: models.KubeconfigUserKeyPair{
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &hostKube, nil
|
||||
}
|
||||
@@ -4,12 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"oc-datacenter/infrastructure"
|
||||
"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"
|
||||
b "cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
@@ -19,10 +20,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 +69,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 +102,43 @@ 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()
|
||||
}
|
||||
|
||||
// @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.(*b.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 +147,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 +155,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")
|
||||
@@ -97,7 +171,7 @@ func (o *BookingController) Check() {
|
||||
}
|
||||
} else {
|
||||
booking := &b.Booking{} // create a new booking object
|
||||
isAvailable, err2 := booking.CheckBooking(id, date, &date2) // check if the booking is available
|
||||
isAvailable, err2 := booking.Check(id, date, &date2, 1) // check if the booking is available
|
||||
fmt.Println(isAvailable, err2)
|
||||
code := 200
|
||||
err := ""
|
||||
@@ -119,9 +193,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 +208,22 @@ 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)
|
||||
var resp booking.Booking
|
||||
user, peerID, groups := oclib.ExtractTokenInfo(*o.Ctx.Request)
|
||||
err := json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &resp)
|
||||
if err != nil {
|
||||
fmt.Println("Error unmarshalling")
|
||||
fmt.Println(err)
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
dc_id := resp.ResourceID
|
||||
// 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: dc_id}},
|
||||
}}, "", isDraft == "true")
|
||||
if res.Code != 200 {
|
||||
o.Data["json"] = map[string]interface{}{
|
||||
"data": nil,
|
||||
@@ -152,37 +234,66 @@ 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."
|
||||
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": res.Code,
|
||||
"error": res.Err + " -> the booking from " + exec.ExecDate.String() + " is already taken.",
|
||||
"code": b.Code,
|
||||
"error": b.Err,
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
fmt.Println("ROLLLLLE BIND")
|
||||
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()
|
||||
}
|
||||
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
|
||||
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.1.169
|
||||
KUBE_CA="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTVlk3ZHZhNEdYTVdkMy9jMlhLN3JLYjlnWXgyNSthaEE0NmkyNVBkSFAKRktQL2UxSVMyWVF0dzNYZW1TTUQxaStZdzJSaVppNUQrSVZUamNtNHdhcnFvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWtlUVJpNFJiODduME5yRnZaWjZHClc2SU55NnN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnRXA5ck04WmdNclRZSHYxZjNzOW5DZXZZeWVVa3lZUk4KWjUzazdoaytJS1FDSVFDbk05TnVGKzlTakIzNDFacGZ5ays2NEpWdkpSM3BhcmVaejdMd2lhNm9kdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
KUBE_CERT="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJWUxWNkFPQkdrU1F3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekl6TVRFeU1ETTJNQjRYRFRJME1EZ3dPREV3TVRNMU5sb1hEVEkxTURndwpPREV3TVRNMU5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJGQ2Q1MFdPeWdlQ2syQzcKV2FrOWY4MVAvSkJieVRIajRWOXBsTEo0ck5HeHFtSjJOb2xROFYxdUx5RjBtOTQ2Nkc0RmRDQ2dqaXFVSk92Swp3NVRPNnd5alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCVFJkOFI5cXVWK2pjeUVmL0ovT1hQSzMyS09XekFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQTArbThqTDBJVldvUTZ0dnB4cFo4NVlMalF1SmpwdXM0aDdnSXRxS3NmUVVDSUI2M2ZNdzFBMm5OVWU1TgpIUGZOcEQwSEtwcVN0Wnk4djIyVzliYlJUNklZCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRc3hXWk9pbnIrcVp4TmFEQjVGMGsvTDF5cE01VHAxOFRaeU92ektJazQKRTFsZWVqUm9STW0zNmhPeVljbnN3d3JoNnhSUnBpMW5RdGhyMzg0S0Z6MlBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBYZkVmYXJsZm8zTWhIL3lmemx6Cnl0OWlqbHN3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUxJL2dNYnNMT3MvUUpJa3U2WHVpRVMwTEE2cEJHMXgKcnBlTnpGdlZOekZsQWlFQW1wdjBubjZqN3M0MVI0QzFNMEpSL0djNE53MHdldlFmZWdEVGF1R2p3cFk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
KUBE_DATA="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5ZS1BFb1dhd1NKUzJlRW5oWmlYMk5VZlY1ZlhKV2krSVNnV09TNFE5VTlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVUozblJZN0tCNEtUWUx0WnFUMS96VS84a0Z2Sk1lUGhYMm1Vc25pczBiR3FZblkyaVZEeApYVzR2SVhTYjNqcm9iZ1YwSUtDT0twUWs2OHJEbE03ckRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
|
||||
46
go.mod
46
go.mod
@@ -1,57 +1,89 @@
|
||||
module oc-datacenter
|
||||
|
||||
go 1.22.0
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.22.4
|
||||
toolchain go1.23.3
|
||||
|
||||
require (
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250110163958-fd1c579ec418
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250219142942-5111c9c8bec7
|
||||
github.com/beego/beego/v2 v2.3.1
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
go.mongodb.org/mongo-driver v1.17.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.32.1
|
||||
k8s.io/apimachinery v0.32.1
|
||||
k8s.io/client-go v0.32.1
|
||||
)
|
||||
|
||||
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/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/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/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nats-io/nats.go v1.37.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // 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/robfig/cron v1.2.0 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect
|
||||
github.com/smartystreets/goconvey v1.7.2 // 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/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/term v0.25.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
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
|
||||
)
|
||||
|
||||
122
go.sum
122
go.sum
@@ -1,10 +1,12 @@
|
||||
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-20250219142942-5111c9c8bec7 h1:fh6SzBPenzIxufIIzExtx4jEE4OhFposqn3EbHFr92Q=
|
||||
cloud.o-forge.io/core/oc-lib v0.0.0-20250219142942-5111c9c8bec7/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
|
||||
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/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=
|
||||
@@ -17,10 +19,24 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/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/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
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,12 +45,29 @@ 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-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
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.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.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=
|
||||
@@ -44,13 +77,22 @@ github.com/goraz/onion v0.1.3/go.mod h1:XEmz1XoBz+wxTgWB8NwuvRm4RAu3vKxvrmYtzK+X
|
||||
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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
@@ -58,6 +100,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
@@ -68,9 +112,12 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
@@ -82,7 +129,12 @@ github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDm
|
||||
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/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/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=
|
||||
@@ -95,10 +147,10 @@ github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPA
|
||||
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/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/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
@@ -111,10 +163,19 @@ 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
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/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,29 +184,42 @@ 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=
|
||||
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/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/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -157,23 +231,59 @@ 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/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.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
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/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-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.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=
|
||||
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
|
||||
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
|
||||
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=
|
||||
k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
||||
37
infrastructure/interface.go
Normal file
37
infrastructure/interface.go
Normal file
@@ -0,0 +1,37 @@
|
||||
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) (*v1.Node, error)
|
||||
}
|
||||
|
||||
var _service = map[string]func() (Infrastructure, error){
|
||||
"kubernetes": NewKubernetesService,
|
||||
}
|
||||
|
||||
func NewService() (Infrastructure, error) {
|
||||
service, ok := _service[conf.GetConfig().Mode]
|
||||
if !ok {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
return service()
|
||||
}
|
||||
|
||||
544
infrastructure/kubernetes.go
Normal file
544
infrastructure/kubernetes.go
Normal file
@@ -0,0 +1,544 @@
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"oc-datacenter/conf"
|
||||
"strings"
|
||||
|
||||
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 {
|
||||
// Delete the namespace
|
||||
if err := k.Set.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}); err != nil {
|
||||
return errors.New("Error deleting namespace: " + err.Error())
|
||||
}
|
||||
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 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 putCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string, body []byte, params ...map[string]string) ([]byte, error){
|
||||
req := client.RESTClient().
|
||||
Post().
|
||||
AbsPath(path).
|
||||
Body(body)
|
||||
|
||||
for _, param := range params {
|
||||
for k, v := range param {
|
||||
req = req.Param(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := req.DoRaw(ctx)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error from k8s API when posting "+string(body)+" to "+path+" : ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, 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) (*v1.Node, error) {
|
||||
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-"+executionID+"-"); isNode {
|
||||
return &node, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, 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(peerId, "-")[:2]
|
||||
p := s[0] + "-" + s[1]
|
||||
|
||||
return p + "-" + namespace
|
||||
}
|
||||
18
main.go
18
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,7 +20,22 @@ 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)
|
||||
}
|
||||
// feed the library with the loaded config
|
||||
oclib.SetConfig(
|
||||
o.GetStringDefault("MONGO_URL", "mongodb://127.0.0.1:27017"),
|
||||
|
||||
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,78 @@ 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:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
|
||||
beego.ControllerComments{
|
||||
Method: "GetAll",
|
||||
@@ -34,6 +106,15 @@ func init() {
|
||||
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",
|
||||
@@ -52,6 +133,42 @@ 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: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,11 @@ func init() {
|
||||
&controllers.VersionController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/admiralty",
|
||||
beego.NSInclude(
|
||||
&controllers.AdmiraltyController{},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
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