implemented the /minio/serviceaccount route to create new serviceAccount in the minio corresponding to the parameter, then store it in secret in the namespace corresponding to the executionsId

This commit is contained in:
pb 2025-06-30 12:33:24 +02:00
parent 625f34ed21
commit a664423842
9 changed files with 206 additions and 7 deletions

View File

@ -1,6 +1,12 @@
package controllers package controllers
import beego "github.com/beego/beego/v2/server/web" import (
"oc-datacenter/infrastructure"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/models/live"
beego "github.com/beego/beego/v2/server/web"
)
type MinioController struct { type MinioController struct {
beego.Controller beego.Controller
@ -12,11 +18,105 @@ type MinioController struct {
// @Success 200 // @Success 200
// @Param executions path string true "The executionsID of the execution" // @Param executions path string true "The executionsID of the execution"
// @Param minioId path string true "The ID of the Minio you want to reach" // @Param minioId path string true "The ID of the Minio you want to reach"
// @router /minio/:minioId/:executions // @router /serviceaccount/:minioId/:executions
func (m *MinioController) CreateServiceAccount() { func (m *MinioController) CreateServiceAccount() {
_, peerID, _ := oclib.ExtractTokenInfo(*m.Ctx.Request)
// This part is solely for dev purposes and should be removed once test on
executionsId := m.Ctx.Input.Param(":executions") executionsId := m.Ctx.Input.Param(":executions")
minioId := m.Ctx.Input.Param(":minioId") minioId := m.Ctx.Input.Param(":minioId")
// retrieve the live storage with the minioId
s := oclib.NewRequest(oclib.LibDataEnum(oclib.STORAGE_RESOURCE), "", "", []string{}, nil).LoadOne(minioId)
if s.Err != "" {
m.Ctx.Output.SetStatus(400)
m.Data["json"] = map[string]interface{}{"error":s.Err}
m.ServeJSON()
return
}
live := findLiveStorage(minioId, peerID)
if live == nil {
m.Ctx.Output.SetStatus(404)
m.Data["json"] = map[string]interface{}{"error":"could not find the Minio instance " + s.Err}
m.ServeJSON()
return
}
m.Data["json"] = map[string]interface{}{"exec": executionsId, "minioId": minioId} url := live.Source
service := infrastructure.NewMinioService(url)
// call the method ctrating the svcacc
err := service.CreateClient()
if err != nil {
m.Ctx.Output.SetStatus(500)
m.Data["json"] = map[string]interface{}{"error":"could not create the client for " + minioId + " : " + err.Error()}
m.ServeJSON()
return
}
access, secret, err := service.CreateCredentials(executionsId)
if err != nil {
m.Ctx.Output.SetStatus(500)
m.Data["json"] = map[string]interface{}{"error":"could not create the service account for " + minioId + " : " + err.Error()}
m.ServeJSON()
return
}
// test if the namespace exists
k, err := infrastructure.NewService()
if err != nil {
m.Ctx.Output.SetStatus(500)
m.Data["json"] = map[string]string{"error": err.Error()}
m.ServeJSON()
return
}
ns, err := k.GetNamespace(m.Ctx.Request.Context(), executionsId)
if ns == nil {
m.Ctx.Output.SetStatus(403)
m.Data["json"] = map[string]string{"error":"Could not find the namespace corresponding to executionsID " + executionsId}
m.ServeJSON()
return
}
if err != nil {
m.Ctx.Output.SetStatus(500)
m.Data["json"] = map[string]string{"error": "Error when trying to check if namespace " + executionsId + " exists : " + err.Error()}
m.ServeJSON()
return
}
// store the credentials in the namespace
err = k.CreateSecret(m.Ctx.Request.Context(), minioId, executionsId, access, secret)
if err != nil {
m.Ctx.Output.SetStatus(500)
m.Data["json"] = map[string]string{"error": "Error when storing Minio serviceAccount credentials in namespace " + executionsId + " exists : " + err.Error()}
m.ServeJSON()
return
}
m.Data["json"] = map[string]string{"access":access,"secret":secret}
m.ServeJSON() m.ServeJSON()
}
func findLiveStorage(storageId string, peerId string) *live.LiveStorage {
res := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_STORAGE),"",peerId,[]string{},nil).LoadAll(false)
if res.Err != "" {
l := oclib.GetLogger()
l.Error().Msg(res.Err)
return nil
}
for _, dbo := range res.Data {
r := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_STORAGE),"","",[]string{},nil).LoadOne(dbo.GetID())
l := r.ToLiveStorage()
for _, id := range l.ResourcesID {
if id == storageId {
return l
}
}
}
return nil
} }

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.24.2
toolchain go1.24.4 toolchain go1.24.4
require ( require (
cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06 cloud.o-forge.io/core/oc-lib v0.0.0-20250626142041-d58dc5602416
github.com/beego/beego/v2 v2.3.8 github.com/beego/beego/v2 v2.3.8
github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang-jwt/jwt/v5 v5.2.2
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3

4
go.sum
View File

@ -1,5 +1,9 @@
cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06 h1:+RSv62uIC7wsmibsp1XTanQMNznNeOGgPpfhb6ZHT4c= cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06 h1:+RSv62uIC7wsmibsp1XTanQMNznNeOGgPpfhb6ZHT4c=
cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI= cloud.o-forge.io/core/oc-lib v0.0.0-20250624102227-e600fedcab06/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250626135921-34b7cdcf06b0 h1:FGWOxAAw3Zh19A2FUeAbttsfuFJ3JDli/un9iCu6uD8=
cloud.o-forge.io/core/oc-lib v0.0.0-20250626135921-34b7cdcf06b0/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250626142041-d58dc5602416 h1:C51EHyggOm2QZ7INqhKOiyapTIbtRi8y2eJjVXzdtnM=
cloud.o-forge.io/core/oc-lib v0.0.0-20250626142041-d58dc5602416/go.mod h1:vHWauJsS6ryf7UDqq8hRXoYD5RsONxcFTxeZPOztEuI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/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 h1:7MUKMpJYzOXtCUsTEoXOxsDV/UcHw6CPbaWMlthVNsc=
github.com/beego/beego/v2 v2.3.1/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4= github.com/beego/beego/v2 v2.3.1/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4=

View File

@ -21,6 +21,8 @@ type Infrastructure interface {
GetKubeconfigSecret(context context.Context, 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) CreateAdmiraltyTarget(context context.Context, executionId string, peerId string) ([]byte, error)
GetOneNode(context context.Context, executionID string, peerId string) (*v1.Node, error) GetOneNode(context context.Context, executionID string, peerId string) (*v1.Node, error)
GetNamespace(context context.Context, executionID string) (*v1.Namespace, error)
CreateSecret(context context.Context, minioId string, executionID string, access string, secret string) error
CheckHealth() error CheckHealth() error
} }

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
oclib "cloud.o-forge.io/core/oc-lib"
authv1 "k8s.io/api/authentication/v1" authv1 "k8s.io/api/authentication/v1"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1" rbacv1 "k8s.io/api/rbac/v1"
@ -26,6 +27,7 @@ import (
var gvrSources = schema.GroupVersionResource{Group: "multicluster.admiralty.io", Version: "v1alpha1", Resource: "sources"} var gvrSources = schema.GroupVersionResource{Group: "multicluster.admiralty.io", Version: "v1alpha1", Resource: "sources"}
var gvrTargets = schema.GroupVersionResource{Group: "multicluster.admiralty.io", Version: "v1alpha1", Resource: "targets"} var gvrTargets = schema.GroupVersionResource{Group: "multicluster.admiralty.io", Version: "v1alpha1", Resource: "targets"}
type KubernetesService struct { type KubernetesService struct {
Set *kubernetes.Clientset Set *kubernetes.Clientset
} }
@ -458,6 +460,21 @@ func (k *KubernetesService) DeleteKubeConfigSecret(executionID string) ([]byte,
return []byte{}, nil return []byte{}, nil
} }
func (k *KubernetesService) GetNamespace(context context.Context, executionID string)(*v1.Namespace,error){
resp, err := k.Set.CoreV1().Namespaces().Get(context,executionID,metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return nil, nil
}
if err != nil {
logger := oclib.GetLogger()
logger.Error().Msg("An error occured when trying to get namespace " + executionID + " : " + err.Error())
return nil, err
}
return resp, nil
}
func getCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string) ([]byte, error) { func getCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string) ([]byte, error) {
resp, err := client.RESTClient().Get(). resp, err := client.RESTClient().Get().
AbsPath(path). AbsPath(path).
@ -566,6 +583,31 @@ func (k *KubernetesService) GetOneNode(context context.Context, executionID stri
return nil, nil return nil, nil
} }
func (k *KubernetesService) CreateSecret(context context.Context, minioId string, executionID string, access string, secret string) error {
data := map[string][]byte{
"access-key": []byte(access),
"secret-key": []byte(secret),
}
s := v1.Secret{
Type: v1.SecretTypeOpaque,
Data: data,
ObjectMeta: metav1.ObjectMeta{
Name: minioId+"-secret-s3",
},
}
_, err := k.Set.CoreV1().Secrets(executionID).Create(context,&s,metav1.CreateOptions{})
if err != nil {
logger := oclib.GetLogger()
logger.Error().Msg("An error happened when creating the secret holding minio credentials in namespace " + executionID + " : " + err.Error())
return err
}
return nil
}
// Returns a concatenation of the peerId and namespace in order for // Returns a concatenation of the peerId and namespace in order for
// kubernetes ressources to have a unique name, under 63 characters // kubernetes ressources to have a unique name, under 63 characters
// and yet identify which peer they are created for // and yet identify which peer they are created for

View File

@ -81,18 +81,19 @@ func (m *MinioService) CreateCredentials(executionId string) (string,string,erro
return "", "", err return "", "", err
} }
return res.AccessKey, res.SecretKey, nil return res.AccessKey, res.SecretKey, nil
} }
func getRandomCreds() (string, string){ func getRandomCreds() (string, string){
opts := randomstring.GenerationOptions{ opts := randomstring.GenerationOptions{
Length: 32, Length: 20,
} }
a, _ := randomstring.GenerateString(opts) a, _ := randomstring.GenerateString(opts)
opts.Length = 64 opts.Length = 40
s, _ := randomstring.GenerateString(opts) s, _ := randomstring.GenerateString(opts)
return a,s return a,s

View File

@ -23,7 +23,7 @@ func main() {
conf.GetConfig().Mode = o.GetStringDefault("MODE", "kubernetes") conf.GetConfig().Mode = o.GetStringDefault("MODE", "kubernetes")
conf.GetConfig().KubeHost = o.GetStringDefault("KUBERNETES_SERVICE_HOST", os.Getenv("KUBERNETES_SERVICE_HOST")) conf.GetConfig().KubeHost = o.GetStringDefault("KUBERNETES_SERVICE_HOST", os.Getenv("KUBERNETES_SERVICE_HOST"))
conf.GetConfig().KubePort = o.GetStringDefault("KUBERNETES_SERVICE_PORT", "6443") conf.GetConfig().KubePort = o.GetStringDefault("KUBERNETES_SERVICE_PORT", "6443")
sDec, err := base64.StdEncoding.DecodeString(o.GetStringDefault("KUBE_CA", "")) sDec, err := base64.StdEncoding.DecodeString(o.GetStringDefault("KUBE_CA", ""))
if err == nil { if err == nil {
conf.GetConfig().KubeCA = string(sDec) conf.GetConfig().KubeCA = string(sDec)

View File

@ -79,6 +79,15 @@ func init() {
Filters: nil, Filters: nil,
Params: nil}) Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:AdmiraltyController"],
beego.ControllerComments{
Method: "DeleteAdmiraltySession",
Router: `/targets/:execution`,
AllowHTTPMethods: []string{"delete"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"], beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
beego.ControllerComments{ beego.ControllerComments{
Method: "GetAll", Method: "GetAll",
@ -106,6 +115,15 @@ func init() {
Filters: nil, Filters: nil,
Params: nil}) Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
beego.ControllerComments{
Method: "Log",
Router: `/:id`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"], beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
beego.ControllerComments{ beego.ControllerComments{
Method: "Put", Method: "Put",
@ -124,6 +142,24 @@ func init() {
Filters: nil, Filters: nil,
Params: nil}) Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
beego.ControllerComments{
Method: "ExtendForExecution",
Router: `/extend/:resource_id/from_execution/:execution_id/to/:duration`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
beego.ControllerComments{
Method: "ExtendForNamespace",
Router: `/extend/:resource_id/from_namespace/:namespace/to/:duration`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"], beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:BookingController"],
beego.ControllerComments{ beego.ControllerComments{
Method: "Search", Method: "Search",
@ -160,6 +196,15 @@ func init() {
Filters: nil, Filters: nil,
Params: nil}) Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:MinioController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:MinioController"],
beego.ControllerComments{
Method: "CreateServiceAccount",
Router: `/serviceaccount/:minioId/:executions`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["oc-datacenter/controllers:SessionController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:SessionController"], beego.GlobalControllerRouter["oc-datacenter/controllers:SessionController"] = append(beego.GlobalControllerRouter["oc-datacenter/controllers:SessionController"],
beego.ControllerComments{ beego.ControllerComments{
Method: "GetToken", Method: "GetToken",

View File

@ -39,6 +39,11 @@ func init() {
&controllers.AdmiraltyController{}, &controllers.AdmiraltyController{},
), ),
), ),
beego.NSNamespace("/minio",
beego.NSInclude(
&controllers.MinioController{},
),
),
) )
beego.AddNamespace(ns) beego.AddNamespace(ns)