draft... metrics by booking...

This commit is contained in:
mr
2025-06-18 08:26:10 +02:00
parent 001539fb36
commit c7290b0ead
8 changed files with 489 additions and 233 deletions

View File

@@ -20,53 +20,50 @@ import (
)
type KubeInfo struct {
Url *string
KubeCA *string
KubeCert *string
KubeKey *string
Url *string
KubeCA *string
KubeCert *string
KubeKey *string
}
type RemoteKubeconfig struct {
Data *string
Data *string
}
type KubeUser struct {
Name string
User struct {
Token string
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"`
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"`
Token string `yaml:"token"`
} `yaml:"user"`
} `yaml:"users"`
}
// Operations about the admiralty objects of the datacenter
type AdmiraltyController struct {
beego.Controller
@@ -74,19 +71,19 @@ type AdmiraltyController struct {
// @Title GetAllTargets
// @Description find all Admiralty Target
// @Success 200
// @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)
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()
@@ -95,7 +92,7 @@ func (c *AdmiraltyController) GetAllTargets() {
// @Title GetOneTarget
// @Description find one Admiralty Target
// @Param id path string true "the name of the target to get"
// @Success 200
// @Success 200
// @router /targets/:execution [get]
func (c *AdmiraltyController) GetOneTarget() {
id := c.Ctx.Input.Param(":execution")
@@ -107,10 +104,10 @@ func (c *AdmiraltyController) GetOneTarget() {
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)
id = "target-" + id
found := slices.Contains(res, id)
if !found {
c.Ctx.Output.SetStatus(404)
c.ServeJSON()
@@ -123,7 +120,7 @@ func (c *AdmiraltyController) GetOneTarget() {
// @Title CreateAdmiraltySource
// @Description Create an Admiralty Source on remote cluster
// @Param execution path string true "execution id of the workflow"
// @Success 201
// @Success 201
// @router /source/:execution [post]
func (c *AdmiraltyController) CreateAdmiraltySource() {
@@ -140,11 +137,11 @@ func (c *AdmiraltyController) CreateAdmiraltySource() {
return
}
res, err := serv.CreateAdmiraltySource(c.Ctx.Request.Context(),execution)
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.Data["json"] = map[string]string{"info": "A source already exists for this namespace : " + execution}
c.ServeJSON()
return
}
@@ -154,15 +151,15 @@ func (c *AdmiraltyController) CreateAdmiraltySource() {
c.ServeJSON()
return
}
// TODO : Return a description of the created resource
var respData map[string]interface{}
err = json.Unmarshal(res,&respData)
err = json.Unmarshal(res, &respData)
c.Ctx.Output.SetStatus(201)
c.Data["json"] = respData
c.ServeJSON()
}
// @Title CreateAdmiraltyTarget
@@ -171,15 +168,15 @@ func (c *AdmiraltyController) CreateAdmiraltySource() {
// @Param peer path string true "peerId of the peer the target points to"
// @Success 201
// @router /target/:execution/:peer [post]
func (c *AdmiraltyController) CreateAdmiraltyTarget(){
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.Data["json"] = map[string]string{"error": "parameters can be empty " + "execution: " + execution + " peer: " + peerId}
c.ServeJSON()
return
}
@@ -193,7 +190,7 @@ func (c *AdmiraltyController) CreateAdmiraltyTarget(){
return
}
resp, err := serv.CreateAdmiraltyTarget(c.Ctx.Request.Context(),execution, peerId)
resp, err := serv.CreateAdmiraltyTarget(c.Ctx.Request.Context(), execution, peerId)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -206,12 +203,12 @@ func (c *AdmiraltyController) CreateAdmiraltyTarget(){
fmt.Println(resp)
fmt.Println(err)
c.Ctx.Output.SetStatus(401)
c.Data["json"] = map[string]string{"error" : "Could not perform the action" }
c.Data["json"] = map[string]string{"error": "Could not perform the action"}
c.ServeJSON()
return
}
err = json.Unmarshal(resp,&data)
err = json.Unmarshal(resp, &data)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -229,15 +226,14 @@ func (c *AdmiraltyController) CreateAdmiraltyTarget(){
// @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
// @Success 200
// @router /secret/:execution/:peer [get]
func(c *AdmiraltyController) GetKubeSecret() {
var data map[string]interface{}
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
@@ -247,7 +243,7 @@ func(c *AdmiraltyController) GetKubeSecret() {
return
}
resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(),execution, peerId)
resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(), execution, peerId)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -260,8 +256,8 @@ func(c *AdmiraltyController) GetKubeSecret() {
c.ServeJSON()
return
}
err = json.Unmarshal(resp,&data)
err = json.Unmarshal(resp, &data)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -274,18 +270,17 @@ func(c *AdmiraltyController) GetKubeSecret() {
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
// @Success 201
// @router /secret/:execution/:peer [post]
func (c *AdmiraltyController) CreateKubeSecret() {
var kubeconfig RemoteKubeconfig
var respData map[string]interface{}
var kubeconfig RemoteKubeconfig
var respData map[string]interface{}
data := c.Ctx.Input.CopyBody(100000)
@@ -311,7 +306,7 @@ func (c *AdmiraltyController) CreateKubeSecret() {
return
}
resp, err := serv.CreateKubeconfigSecret(c.Ctx.Request.Context(),*kubeconfig.Data,execution, peerId)
resp, err := serv.CreateKubeconfigSecret(c.Ctx.Request.Context(), *kubeconfig.Data, execution, peerId)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -320,7 +315,7 @@ func (c *AdmiraltyController) CreateKubeSecret() {
return
}
err = json.Unmarshal(resp,&respData)
err = json.Unmarshal(resp, &respData)
c.Ctx.Output.SetStatus(201)
c.Data["json"] = respData
c.ServeJSON()
@@ -331,9 +326,9 @@ func (c *AdmiraltyController) CreateKubeSecret() {
// @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
// @Success 200
// @router /node/:execution/:peer [get]
func (c *AdmiraltyController) GetNodeReady(){
func (c *AdmiraltyController) GetNodeReady() {
var secret v1.Secret
execution := c.Ctx.Input.Param(":execution")
peerId := c.Ctx.Input.Param(":peer")
@@ -347,7 +342,7 @@ func (c *AdmiraltyController) GetNodeReady(){
return
}
node, err := serv.GetOneNode(c.Ctx.Request.Context(),execution, peerId)
node, err := serv.GetOneNode(c.Ctx.Request.Context(), execution, peerId)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -358,15 +353,13 @@ func (c *AdmiraltyController) GetNodeReady(){
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",
"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)
resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(), execution, peerId)
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
@@ -383,26 +376,26 @@ func (c *AdmiraltyController) GetNodeReady(){
// Extract JWT token RS265 encoded
var editedKubeconfig map[string]interface{}
json.Unmarshal(resp,&secret)
json.Unmarshal(resp, &secret)
byteEditedKubeconfig := secret.Data["config"]
err = yaml.Unmarshal(byteEditedKubeconfig,&editedKubeconfig)
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("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)
HandleControllerErrors(c.Controller, 500, &err, nil)
}
// Decode token
isExpired, err := isTokenExpired(token)
if err != nil {
@@ -414,19 +407,19 @@ func (c *AdmiraltyController) GetNodeReady(){
if *isExpired {
c.Data["json"] = map[string]interface{}{
"token" : "token in the secret is expired and must be regenerated",
"node": node,
"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.Data["json"] = map[string]interface{}{"node": node, "token": true}
c.ServeJSON()
}
func retrieveTokenFromKonfig(editedKubeconfig map[string]interface{}) (string,error) {
func retrieveTokenFromKonfig(editedKubeconfig map[string]interface{}) (string, error) {
var kubeUsers []KubeUser
b, err := yaml.Marshal(editedKubeconfig["users"])
if err != nil {
@@ -434,7 +427,7 @@ func retrieveTokenFromKonfig(editedKubeconfig map[string]interface{}) (string,er
fmt.Println(err)
return "", err
}
err = yaml.Unmarshal(b,&kubeUsers)
err = yaml.Unmarshal(b, &kubeUsers)
if err != nil {
fmt.Println("Error while unmarshalling users attribute from kubeconfig")
fmt.Println(err)
@@ -446,7 +439,7 @@ func retrieveTokenFromKonfig(editedKubeconfig map[string]interface{}) (string,er
return token, nil
}
func isTokenExpired(token string) (*bool, error){
func isTokenExpired(token string) (*bool, error) {
logger := oclib.GetLogger()
t, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
@@ -465,22 +458,20 @@ func isTokenExpired(token string) (*bool, error){
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
// @Success 200
// @router /kubeconfig/:execution [get]
func (c *AdmiraltyController) GetAdmiraltyKubeconfig() {
execution := c.Ctx.Input.Param(":execution")
execution := c.Ctx.Input.Param(":execution")
serv, err := infrastructure.NewService()
if err != nil {
@@ -491,7 +482,7 @@ func (c *AdmiraltyController) GetAdmiraltyKubeconfig() {
return
}
generatedToken, err := serv.GenerateToken(c.Ctx.Request.Context(),execution,3600)
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)
@@ -523,12 +514,11 @@ func (c *AdmiraltyController) GetAdmiraltyKubeconfig() {
c.Data["json"] = map[string]string{
"data": encodedKubeconfig,
}
json.NewEncoder(c.Ctx.ResponseWriter)
c.ServeJSON()
}
func NewHostKubeWithToken(token string) (*models.KubeConfigValue, error){
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")
}
@@ -536,15 +526,15 @@ func NewHostKubeWithToken(token string) (*models.KubeConfigValue, error){
encodedCA := base64.StdEncoding.EncodeToString([]byte(conf.GetConfig().KubeCA))
hostKube := models.KubeConfigValue{
APIVersion: "v1",
APIVersion: "v1",
CurrentContext: "default",
Kind: "Config",
Preferences: struct{}{},
Kind: "Config",
Preferences: struct{}{},
Clusters: []models.KubeconfigNamedCluster{
{
Name: "default",
Cluster: models.KubeconfigCluster{
Server: "https://" + conf.GetConfig().KubeHost + ":6443",
Server: "https://" + conf.GetConfig().KubeHost + ":6443",
CertificateAuthorityData: encodedCA,
},
},
@@ -554,12 +544,12 @@ func NewHostKubeWithToken(token string) (*models.KubeConfigValue, error){
Name: "default",
Context: models.KubeconfigContext{
Cluster: "default",
User: "default",
User: "default",
},
},
},
Users: []models.KubeconfigUser{
models.KubeconfigUser{
{
Name: "default",
User: models.KubeconfigUserKeyPair{
Token: token,
@@ -569,4 +559,4 @@ func NewHostKubeWithToken(token string) (*models.KubeConfigValue, error){
}
return &hostKube, nil
}
}

View File

@@ -11,6 +11,7 @@ import (
"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/tools"
beego "github.com/beego/beego/v2/server/web"
"go.mongodb.org/mongo-driver/bson/primitive"
)
@@ -212,17 +213,51 @@ func (o *BookingController) Post() {
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)
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 422,
"error": err,
}
o.ServeJSON()
return
}
if resp.ResourceType == tools.COMPUTE_RESOURCE {
// later should check... health for any such as docker...
res := oclib.NewRequest(oclib.LibDataEnum(oclib.COMPUTE_RESOURCE), user, peerID, groups, nil).LoadOne(resp.ResourceID)
if res.Err != "" {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": res.Code,
"error": res.Err,
}
o.ServeJSON()
return
}
serv, err := infrastructure.NewServiceByType(res.ToComputeResource().Infrastructure.String())
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 500,
"error": err,
}
o.ServeJSON()
return
}
if err := serv.CheckHealth(); err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 500,
"error": err,
}
o.ServeJSON()
return
}
}
dc_id := resp.ResourceID
// delete all previous bookings
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}},
"resource_id": {{Operator: dbs.EQUAL.String(), Value: resp.ResourceID}},
}}, "", isDraft == "true")
if res.Code != 200 {
o.Data["json"] = map[string]interface{}{