12 Commits

27 changed files with 234 additions and 1272 deletions

1
.gitignore vendored
View File

@@ -0,0 +1 @@
swagger/

View File

@@ -1,5 +1,3 @@
ARG KUBERNETES_HOST=${KUBERNETES_HOST:-"127.0.0.1"}
FROM golang:alpine AS deps FROM golang:alpine AS deps
WORKDIR /app WORKDIR /app
@@ -30,7 +28,7 @@ RUN export CGO_ENABLED=0 && \
COPY . . COPY . .
RUN sed -i '/replace/d' go.mod RUN sed -i '/replace/d' go.mod
RUN if [ ! -f swagger/index.html ]; then timeout 15 bee run --gendoc=true --downdoc=true; fi RUN if [ ! -f swagger/index.html ]; then timeout 15 bee run -gendoc=true -downdoc=true; fi
RUN bee generate routers RUN bee generate routers
RUN bee generate docs RUN bee generate docs
RUN bee pack RUN bee pack
@@ -41,8 +39,6 @@ RUN sed -i 's/http:\/\/127.0.0.1:8080\/swagger\/swagger.json/swagger.json/g' /ap
FROM golang:alpine FROM golang:alpine
ENV KUBERNETES_SERVICE_HOST=$KUBERNETES_HOST
WORKDIR /app WORKDIR /app
COPY --from=builder /app/extracted/oc-datacenter /usr/bin/ COPY --from=builder /app/extracted/oc-datacenter /usr/bin/
COPY --from=builder /app/extracted/swagger /app/swagger COPY --from=builder /app/extracted/swagger /app/swagger

View File

@@ -10,10 +10,13 @@ import (
"slices" "slices"
"time" "time"
oclib "cloud.o-forge.io/core/oc-lib"
beego "github.com/beego/beego/v2/server/web" beego "github.com/beego/beego/v2/server/web"
jwt "github.com/golang-jwt/jwt/v5" jwt "github.com/golang-jwt/jwt/v5"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
) )
type KubeInfo struct { type KubeInfo struct {
@@ -139,6 +142,12 @@ func (c *AdmiraltyController) CreateSource() {
res, err := serv.CreateAdmiraltySource(c.Ctx.Request.Context(),execution) res, err := serv.CreateAdmiraltySource(c.Ctx.Request.Context(),execution)
if err != nil { 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 // change code to 500
c.Ctx.Output.SetStatus(500) c.Ctx.Output.SetStatus(500)
c.Data["json"] = map[string]string{"error": err.Error()} c.Data["json"] = map[string]string{"error": err.Error()}
@@ -315,7 +324,6 @@ func (c *AdmiraltyController) CreateKubeSecret() {
// @router /node/:execution [get] // @router /node/:execution [get]
func (c *AdmiraltyController) GetNodeReady(){ func (c *AdmiraltyController) GetNodeReady(){
var secret v1.Secret var secret v1.Secret
execution := c.Ctx.Input.Param(":execution") execution := c.Ctx.Input.Param(":execution")
@@ -339,12 +347,14 @@ func (c *AdmiraltyController) GetNodeReady(){
if node == nil { if node == nil {
c.Ctx.Output.SetStatus(404) c.Ctx.Output.SetStatus(404)
c.Data["json"] = map[string]string{ c.Data["json"] = map[string]string{
"error" : "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() c.ServeJSON()
return return
} }
resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(),execution) resp, err := serv.GetKubeconfigSecret(c.Ctx.Request.Context(),execution)
if err != nil { if err != nil {
// change code to 500 // change code to 500
@@ -359,7 +369,6 @@ func (c *AdmiraltyController) GetNodeReady(){
c.ServeJSON() c.ServeJSON()
return return
} }
// Extract JWT token RS265 encoded // Extract JWT token RS265 encoded
var editedKubeconfig map[string]interface{} var editedKubeconfig map[string]interface{}
@@ -393,14 +402,15 @@ func (c *AdmiraltyController) GetNodeReady(){
} }
if *isExpired { if *isExpired {
c.Data["json"] = map[string]string{ c.Data["json"] = map[string]interface{}{
"token" : "token in the secret is expired and must be regenerated", "token" : "token in the secret is expired and must be regenerated",
"node": node,
} }
c.Ctx.Output.SetStatus(410) c.Ctx.Output.SetStatus(410)
c.ServeJSON() c.ServeJSON()
} }
c.Data["json"] = map[string]bool{"ok": true} c.Data["json"] = map[string]interface{}{"node": node,"token": true}
c.ServeJSON() c.ServeJSON()
} }
@@ -426,6 +436,8 @@ func retrieveTokenFromKonfig(editedKubeconfig map[string]interface{}) (string,er
} }
func isTokenExpired(token string) (*bool, error){ func isTokenExpired(token string) (*bool, error){
logger := oclib.GetLogger()
t, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{}) t, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
if err != nil { if err != nil {
fmt.Println("couldn't decode token") fmt.Println("couldn't decode token")
@@ -437,7 +449,11 @@ func isTokenExpired(token string) (*bool, error){
fmt.Println("Error while checking token's expiration time") fmt.Println("Error while checking token's expiration time")
return nil, err return nil, err
} }
fmt.Println("Expiration date : " + expiration.UTC().Format("2006-01-02T15:04:05"))
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() expired := expiration.Unix() < time.Now().Unix()

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"oc-datacenter/infrastructure" "oc-datacenter/infrastructure"
"strings"
"time" "time"
oclib "cloud.o-forge.io/core/oc-lib" oclib "cloud.o-forge.io/core/oc-lib"
@@ -246,11 +247,19 @@ func (o *BookingController) Post() {
o.ServeJSON() o.ServeJSON()
return return
} }
if err := o.createNamespace(resp.ExecutionsID); err != nil {
/*if err := o.createNamespace(resp.ExecutionsID); err != nil { if strings.Contains(err.Error(), "already exists") {
fmt.Println(err.Error()) err = nil
}*/ } else {
o.Data["json"] = map[string]interface{}{
"data": nil,
"code": 500,
"error": err.Error(),
}
o.ServeJSON()
return
}
}
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": []interface{}{b}, "data": []interface{}{b},
"code": 200, "code": 200,

View File

@@ -3,5 +3,8 @@
"NATS_URL": "nats://localhost:4222", "NATS_URL": "nats://localhost:4222",
"MONGO_DATABASE": "DC_myDC", "MONGO_DATABASE": "DC_myDC",
"KUBERNETES_SERVICE_HOST": "172.16.0.183", "KUBERNETES_SERVICE_HOST": "172.16.0.183",
"port": "8092" "port": "8092",
"KUBE_CA": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTXpnNE5UazJNVFl3SGhjTk1qVXdNakEyTVRZek16TTJXaGNOTXpVd01qQTBNVFl6TXpNMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTXpnNE5UazJNVFl3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSbi9jVmNUb1orekZUdWZSL29qbG5JMnVpZXJYeTkxcWhxYWpHdWVobXYKV1A4NVQ1dXpkcE1rcFhrNnB5bTlFU0RlRjk1WDFkeTJqdjVFR3paZzZ2WWtvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXJRK0xUR2NMNXBENnBxSEozaVh5CmZiMFRQUDR3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUlObXp3ejhOUVRCNFlURlZJd3BudDhpQjJ5alRlQjYKbkZxRUN6SWw0amUzQWlFQW04dzRma1h0UEhzUG1Yc0hhUXFGSkhkUm9SQ1pSa016akU3REdZY1lMNVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
"KUBE_CERT": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJYVlyeG5xbm54WEl3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOek00T0RVNU5qRTJNQjRYRFRJMU1ESXdOakUyTXpNek5sb1hEVEkyTURJdwpOakUyTXpNek5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJHeDVVb1Ura01obE9xeHgKTjhRV1FOOGF1ekxXRHpjZTBVbnRYWFdHUmFvWHdHdnlYUldkaFlQcVNoU0xJVGttMG5GV2t5cEZlNUdXTXJlVApZd0hReE9talNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCU0ZlbDVtUXNEaW1vMCtEUzZZZWM1QXdDRXFWREFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQWs3U3UrV3RmQks4SmVPazRreVFVdEFtMkxoak8zV25qOW5SdW9HbVpyTGdDSUJwdVNnNU5oMjUrYm1xMgpZQ2xEM3NLTGdQM1ZKUitCYytxS3h3UjVHbmJwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTXpnNE5UazJNVFl3SGhjTk1qVXdNakEyTVRZek16TTJXaGNOTXpVd01qQTBNVFl6TXpNMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTXpnNE5UazJNVFl3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSTDJSZ1U5RHJZazhKUm4xeDlWSVI3eU5hdWVjaFZuK1pRdDVyeDZaalYKeFRSd0RFT0xXZ1MvbkNpYkp6eUVFNmhLUDVzczBPdnp0ZzlxeFZYU1orNzBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWhYcGVaa0xBNHBxTlBnMHVtSG5PClFNQWhLbFF3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnS09hYVMyczRSWWgrU3J0TXpXTnVtVHduajlKOTZuWUkKL0prdEhjNU5lQnNDSVFDbTY5a1U3cDA5V3hHYWdkNmRQbUlOQ09Fa2V2bzZoQ0dNQTNpd0ZlZ3BiQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
"KUBE_DATA": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU0yYUxXTmtPQ2ZGRTJxM2V1VE9kaHd0RXdxTWRaVUZTTlRPOG50OER0K1RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFYkhsU2hUNlF5R1U2ckhFM3hCWkEzeHE3TXRZUE54N1JTZTFkZFlaRnFoZkFhL0pkRloyRgpnK3BLRklzaE9TYlNjVmFUS2tWN2taWXl0NU5qQWRERTZRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
} }

View File

@@ -2,9 +2,6 @@ version: '3.4'
services: services:
oc-datacenter: oc-datacenter:
env_file:
- path: ./env.env
required: false
environment: environment:
- MONGO_DATABASE=DC_myDC - MONGO_DATABASE=DC_myDC
image: 'oc-datacenter:latest' image: 'oc-datacenter:latest'

View File

@@ -1,5 +1,9 @@
{ {
"MONGO_URL":"mongodb://mongo:27017/", "MONGO_URL":"mongodb://mongo:27017/",
"NATS_URL":"nats://nats:4222", "NATS_URL":"nats://nats:4222",
"MONGO_DATABASE":"DC_myDC" "MONGO_DATABASE":"DC_myDC",
"KUBERNETES_SERVICE_HOST" : "172.16.0.181",
"KUBE_CA" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTXpnNE5UazJNVFl3SGhjTk1qVXdNakEyTVRZek16TTJXaGNOTXpVd01qQTBNVFl6TXpNMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTXpnNE5UazJNVFl3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSbi9jVmNUb1orekZUdWZSL29qbG5JMnVpZXJYeTkxcWhxYWpHdWVobXYKV1A4NVQ1dXpkcE1rcFhrNnB5bTlFU0RlRjk1WDFkeTJqdjVFR3paZzZ2WWtvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXJRK0xUR2NMNXBENnBxSEozaVh5CmZiMFRQUDR3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUlObXp3ejhOUVRCNFlURlZJd3BudDhpQjJ5alRlQjYKbkZxRUN6SWw0amUzQWlFQW04dzRma1h0UEhzUG1Yc0hhUXFGSkhkUm9SQ1pSa016akU3REdZY1lMNVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
"KUBE_CERT":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJYVlyeG5xbm54WEl3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOek00T0RVNU5qRTJNQjRYRFRJMU1ESXdOakUyTXpNek5sb1hEVEkyTURJdwpOakUyTXpNek5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJHeDVVb1Ura01obE9xeHgKTjhRV1FOOGF1ekxXRHpjZTBVbnRYWFdHUmFvWHdHdnlYUldkaFlQcVNoU0xJVGttMG5GV2t5cEZlNUdXTXJlVApZd0hReE9talNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCU0ZlbDVtUXNEaW1vMCtEUzZZZWM1QXdDRXFWREFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQWs3U3UrV3RmQks4SmVPazRreVFVdEFtMkxoak8zV25qOW5SdW9HbVpyTGdDSUJwdVNnNU5oMjUrYm1xMgpZQ2xEM3NLTGdQM1ZKUitCYytxS3h3UjVHbmJwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTXpnNE5UazJNVFl3SGhjTk1qVXdNakEyTVRZek16TTJXaGNOTXpVd01qQTBNVFl6TXpNMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTXpnNE5UazJNVFl3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSTDJSZ1U5RHJZazhKUm4xeDlWSVI3eU5hdWVjaFZuK1pRdDVyeDZaalYKeFRSd0RFT0xXZ1MvbkNpYkp6eUVFNmhLUDVzczBPdnp0ZzlxeFZYU1orNzBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWhYcGVaa0xBNHBxTlBnMHVtSG5PClFNQWhLbFF3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnS09hYVMyczRSWWgrU3J0TXpXTnVtVHduajlKOTZuWUkKL0prdEhjNU5lQnNDSVFDbTY5a1U3cDA5V3hHYWdkNmRQbUlOQ09Fa2V2bzZoQ0dNQTNpd0ZlZ3BiQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
"KUBE_DATA": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU0yYUxXTmtPQ2ZGRTJxM2V1VE9kaHd0RXdxTWRaVUZTTlRPOG50OER0K1RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFYkhsU2hUNlF5R1U2ckhFM3hCWkEzeHE3TXRZUE54N1JTZTFkZFlaRnFoZkFhL0pkRloyRgpnK3BLRklzaE9TYlNjVmFUS2tWN2taWXl0NU5qQWRERTZRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
} }

View File

@@ -1,4 +0,0 @@
KUBERNETES_SERVICE_HOST=kubernetes.default.svc.cluster.local
KUBE_CA="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkakNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTnpNeE1qY3dPVFl3SGhjTk1qWXdNekV3TURjeE9ERTJXaGNOTXpZd016QTNNRGN4T0RFMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTnpNeE1qY3dPVFl3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReG81cXQ0MGxEekczRHJKTE1wRVBrd0ZBY1FmbC8vVE1iWjZzemMreHAKbmVzVzRTSTdXK1lWdFpRYklmV2xBMTRaazQvRFlDMHc1YlgxZU94RVVuL0pvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXBLM2pGK25IRlZSbDcwb3ZRVGZnCmZabGNQZE13Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVnkyaUx0Y0xaYm1vTnVoVHdKbU5sWlo3RVlBYjJKNW0KSjJYbG1UbVF5a2tDSUhLbzczaDBkdEtUZTlSa0NXYTJNdStkS1FzOXRFU0tBV0x1emlnYXBHYysKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
KUBE_CERT="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrakNDQVRlZ0F3SUJBZ0lJQUkvSUg2R2Rodm93Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOemN6TVRJM01EazJNQjRYRFRJMk1ETXhNREEzTVRneE5sb1hEVEkzTURNeApNREEzTVRneE5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJQTTdBVEZQSmFMMjUrdzAKUU1vZUIxV2hBRW4vWnViM0tSRERrYnowOFhwQWJ2akVpdmdnTkdpdG4wVmVsaEZHamRmNHpBT29Nd1J3M21kbgpYSGtHVDB5alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCUVZLOThaMEMxcFFyVFJSMGVLZHhIa2o0ejFJREFLQmdncWhrak9QUVFEQWdOSkFEQkcKQWlFQXZYWll6Zk9iSUtlWTRtclNsRmt4ZS80a0E4K01ieDc1UDFKRmNlRS8xdGNDSVFDNnM0ZXlZclhQYmNWSgpxZm5EamkrZ1RacGttN0tWSTZTYTlZN2FSRGFabUE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCZURDQ0FSMmdBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwClpXNTBMV05oUURFM056TXhNamN3T1RZd0hoY05Nall3TXpFd01EY3hPREUyV2hjTk16WXdNekEzTURjeE9ERTIKV2pBak1TRXdId1lEVlFRRERCaHJNM010WTJ4cFpXNTBMV05oUURFM056TXhNamN3T1RZd1dUQVRCZ2NxaGtqTwpQUUlCQmdncWhrak9QUU1CQndOQ0FBUzV1NGVJbStvVnV1SFI0aTZIOU1kVzlyUHdJbFVPNFhIMEJWaDRUTGNlCkNkMnRBbFVXUW5FakxMdlpDWlVaYTlzTlhKOUVtWWt5S0dtQWR2TE9FbUVrbzBJd1FEQU9CZ05WSFE4QkFmOEUKQkFNQ0FxUXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QWRCZ05WSFE0RUZnUVVGU3ZmR2RBdGFVSzAwVWRIaW5jUgo1SStNOVNBd0NnWUlLb1pJemowRUF3SURTUUF3UmdJaEFMY2xtQnR4TnpSVlBvV2hoVEVKSkM1Z3VNSGsvcFZpCjFvYXJ2UVJxTWRKcUFpRUEyR1dNTzlhZFFYTEQwbFZKdHZMVkc1M3I0M0lxMHpEUUQwbTExMVZyL1MwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
KUBE_DATA="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVkSTRZN3lRU1ZwRGNrblhsQmJEaXBWZHRMWEVsYVBkN3VBZHdBWFFya2xvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFOHpzQk1VOGxvdmJuN0RSQXloNEhWYUVBU2Y5bTV2Y3BFTU9SdlBUeGVrQnUrTVNLK0NBMAphSzJmUlY2V0VVYU4xL2pNQTZnekJIRGVaMmRjZVFaUFRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="

View File

@@ -1,13 +1,11 @@
package infrastructure package infrastructure
import ( import (
"bytes"
"context" "context"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"html/template"
"oc-datacenter/conf" "oc-datacenter/conf"
"strings" "strings"
@@ -16,12 +14,40 @@ import (
rbacv1 "k8s.io/api/rbac/v1" rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/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/kubernetes"
"k8s.io/client-go/rest" "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 { type KubernetesService struct {
Set *kubernetes.Clientset 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) { func NewKubernetesService() (Infrastructure, error) {
@@ -33,6 +59,7 @@ func NewKubernetesService() (Infrastructure, error) {
KeyData: []byte(conf.GetConfig().KubeData), KeyData: []byte(conf.GetConfig().KubeData),
}, },
} }
// Create clientset // Create clientset
clientset, err := kubernetes.NewForConfig(config) clientset, err := kubernetes.NewForConfig(config)
fmt.Println("NewForConfig", clientset, err) fmt.Println("NewForConfig", clientset, err)
@@ -43,6 +70,7 @@ func NewKubernetesService() (Infrastructure, error) {
return nil, errors.New("Error creating Kubernetes client: clientset is nil") return nil, errors.New("Error creating Kubernetes client: clientset is nil")
} }
return &KubernetesService{ return &KubernetesService{
Set: clientset, Set: clientset,
}, nil }, nil
@@ -82,6 +110,9 @@ func (k *KubernetesService) CreateNamespace(ctx context.Context, ns string) erro
namespace := &v1.Namespace{ namespace := &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: ns, Name: ns,
Labels: map[string]string{
"multicluster-scheduler":"enabled",
},
}, },
} }
// Create the namespace // Create the namespace
@@ -195,25 +226,27 @@ func (k *KubernetesService) GenerateToken(ctx context.Context, ns string, durati
return token.Status.Token, nil return token.Status.Token, nil
} }
// Needs refactoring : // Needs refactoring :
// - Retrieving the metada (in a method that Unmarshall the part of the json in a metadata object) // - 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) { func (k *KubernetesService) GetTargets(ctx context.Context) ([]string,error){
var listTargets []string var listTargets []string
resp, err := getCDRapiKube(*k.Set, ctx, "/apis/multicluster.admiralty.io/v1alpha1/targets") resp, err := getCDRapiKube(*k.Set, ctx,"/apis/multicluster.admiralty.io/v1alpha1/targets")
if err != nil { if err != nil {
return nil, err return nil,err
} }
fmt.Println(string(resp)) fmt.Println(string(resp))
var targetDict map[string]interface{} var targetDict map[string]interface{}
err = json.Unmarshal(resp, &targetDict) err = json.Unmarshal(resp,&targetDict)
if err != nil { if err != nil {
fmt.Println("TODO: handle the error when unmarshalling k8s API response") fmt.Println("TODO: handle the error when unmarshalling k8s API response")
return nil, err return nil, err
} }
b, _ := json.MarshalIndent(targetDict, "", " ") b, _ := json.MarshalIndent(targetDict,""," ")
fmt.Println(string(b)) fmt.Println(string(b))
data := targetDict["items"].([]interface{}) data := targetDict["items"].([]interface{})
@@ -222,25 +255,25 @@ func (k *KubernetesService) GetTargets(ctx context.Context) ([]string, error) {
var metadata metav1.ObjectMeta var metadata metav1.ObjectMeta
item := item.(map[string]interface{}) item := item.(map[string]interface{})
byteMetada, err := json.Marshal(item["metadata"]) byteMetada, err := json.Marshal(item["metadata"])
if err != nil { if err != nil {
fmt.Println("Error while Marshalling metadata field") fmt.Println("Error while Marshalling metadata field")
return nil, err return nil,err
} }
err = json.Unmarshal(byteMetada, &metadata) err = json.Unmarshal(byteMetada,&metadata)
if err != nil { if err != nil {
fmt.Println("Error while Unmarshalling metadata field to the library object") fmt.Println("Error while Unmarshalling metadata field to the library object")
return nil, err return nil,err
} }
listTargets = append(listTargets, metadata.Name) listTargets = append(listTargets, metadata.Name)
} }
return listTargets, nil return listTargets,nil
} }
// Admiralty Target allows a cluster to deploy pods to remote cluster // Admiralty Target allows a cluster to deploy pods to remote cluster
// //
// The remote cluster must : // The remote cluster must :
// //
@@ -248,47 +281,44 @@ func (k *KubernetesService) GetTargets(ctx context.Context) ([]string, error) {
// //
// - have declared the same namespace as the one where the pods are created in the local cluster // - 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 // - have delcared a serviceAccount with sufficient permission to create pods
func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context, executionId string) ([]byte, error) { func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context,executionId string)([]byte,error){
exists, err := k.GetKubeconfigSecret(context, executionId) exists, err := k.GetKubeconfigSecret(context,executionId)
if err != nil { if err != nil {
fmt.Println("Error verifying kube-secret before creating target") fmt.Println("Error verifying kube-secret before creating target")
return nil, err return nil, err
} }
if exists == nil { if exists == nil {
fmt.Println("Target needs to be binded to a secret in namespace ", executionId) 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 return nil, nil // Maybe we could create a wrapper for errors and add more info to have
} }
var targetManifest string target := map[string]interface{}{
var tpl bytes.Buffer "apiVersion": "multicluster.admiralty.io/v1alpha1",
tmpl, err := template.New("target"). "kind": "Target",
Parse("{\"apiVersion\": \"multicluster.admiralty.io/v1alpha1\", \"kind\": \"Target\", \"metadata\": {\"name\": \"target-{{.ExecutionId}}\"}, \"spec\": { \"kubeconfigSecret\" :{\"name\": \"kube-secret-{{.ExecutionId}}\"}} }") "metadata": map[string]interface{}{
"name": "target-"+executionId,
"namespace": executionId,
},
"spec": map[string]interface{}{
"kubeconfigSecret": map[string]string{
"name" : "kube-secret-"+executionId,
},
},
}
res, err := dynamicClientApply(executionId, "target", gvrTargets, context, target)
if err != nil { if err != nil {
fmt.Println("Error creating the template for the target Manifest") return nil, errors.New("Error when trying to apply Source definition :" + err.Error())
return nil, err
} }
err = tmpl.Execute(&tpl, map[string]string{"ExecutionId": executionId}) return res, nil
targetManifest = tpl.String()
resp, err := postCDRapiKube(
*k.Set,
context,
"/apis/multicluster.admiralty.io/v1alpha1/namespaces/"+executionId+"/targets",
[]byte(targetManifest),
map[string]string{"fieldManager": "kubectl-client-side-apply"},
map[string]string{"fieldValidation": "Strict"},
)
if err != nil {
fmt.Println("Error trying to create a Source on remote cluster : ", err, " : ", resp)
return nil, err
}
return resp, nil
} }
// Admiralty Source allows a cluster to receive pods from a remote cluster // 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. // The source must be associated to a serviceAccount, which will execute the pods locally.
@@ -297,40 +327,32 @@ func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context, execu
// This method is temporary to implement the use of Admiralty, but must be edited // 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 // to rather contact the oc-datacenter from the remote cluster to create the source
// locally and retrieve the token for the serviceAccount // locally and retrieve the token for the serviceAccount
func (k *KubernetesService) CreateAdmiraltySource(context context.Context, executionId string) ([]byte, error) { func (k *KubernetesService) CreateAdmiraltySource(context context.Context,executionId string) ([]byte, error) {
var sourceManifest string
var tpl bytes.Buffer source := map[string]interface{}{
tmpl, err := template.New("source"). "apiVersion": "multicluster.admiralty.io/v1alpha1",
Parse("{\"apiVersion\": \"multicluster.admiralty.io/v1alpha1\", \"kind\": \"Source\", \"metadata\": {\"name\": \"source-{{.ExecutionId}}\"}, \"spec\": {\"serviceAccountName\": \"sa-{{.ExecutionId}}\"} }") "kind": "Source",
"metadata": map[string]interface{}{
"name": "source-"+executionId,
"namespace": executionId,
},
"spec": map[string]interface{}{
"serviceAccountName": "sa-"+executionId,
},
}
res, err := dynamicClientApply(executionId, "source",gvrSources, context, source)
if err != nil { if err != nil {
fmt.Println("Error creating the template for the source Manifest") return nil, errors.New("Error when trying to apply Source definition :" + err.Error())
return nil, err
} }
err = tmpl.Execute(&tpl, map[string]string{"ExecutionId": executionId}) return res, nil
sourceManifest = tpl.String()
resp, err := postCDRapiKube(
*k.Set,
context,
"/apis/multicluster.admiralty.io/v1alpha1/namespaces/"+executionId+"/sources",
[]byte(sourceManifest),
map[string]string{"fieldManager": "kubectl-client-side-apply"},
map[string]string{"fieldValidation": "Strict"},
)
// We can add more info to the log with the content of resp if not nil
if err != nil {
fmt.Println("Error trying to create a Source on remote cluster : ", err, " : ", resp)
return nil, err
}
return resp, nil
} }
// Create a secret from a kubeconfing. Use it to create the secret binded to an Admiralty // 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 // target, which must contain the serviceAccount's token value
func (k *KubernetesService) CreateKubeconfigSecret(context context.Context, kubeconfig string, executionId string) ([]byte, error) { func (k *KubernetesService) CreateKubeconfigSecret(context context.Context,kubeconfig string, executionId string) ([]byte, error) {
config, err := base64.StdEncoding.DecodeString(kubeconfig) config, err := base64.StdEncoding.DecodeString(kubeconfig)
// config, err := base64.RawStdEncoding.DecodeString(kubeconfig) // config, err := base64.RawStdEncoding.DecodeString(kubeconfig)
if err != nil { if err != nil {
@@ -339,35 +361,40 @@ func (k *KubernetesService) CreateKubeconfigSecret(context context.Context, kube
return nil, err return nil, err
} }
secretManifest := &v1.Secret{ secretApplyConfig := apply.Secret("kube-secret-" + executionId,
ObjectMeta: metav1.ObjectMeta{ executionId).
Name: "kube-secret-" + executionId, WithData(map[string][]byte{
Namespace: executionId, "config": config,
}, },
Data: 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
// }
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(). resp, err := k.Set.CoreV1().
Secrets(executionId). Secrets(executionId).
Create(context, secretManifest, metav1.CreateOptions{}) Apply(context,
secretApplyConfig,
metav1.ApplyOptions{
FieldManager: "admiralty-manager",
})
if err != nil { if err != nil {
fmt.Println("Error while trying to contact API to get secret kube-secret-" + executionId) fmt.Println("Error while trying to contact API to get secret kube-secret-"+executionId)
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
} }
@@ -379,19 +406,19 @@ func (k *KubernetesService) CreateKubeconfigSecret(context context.Context, kube
return nil, err return nil, err
} }
return data, nil return data, nil
} }
func (k *KubernetesService) GetKubeconfigSecret(context context.Context, executionId string) ([]byte, error) { func (k *KubernetesService) GetKubeconfigSecret(context context.Context,executionId string) ([]byte, error) {
resp, err := k.Set.CoreV1(). resp, err := k.Set.CoreV1().
Secrets(executionId). Secrets(executionId).
Get(context, "kube-secret-"+executionId, metav1.GetOptions{}) Get(context,"kube-secret-"+executionId,metav1.GetOptions{})
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if(apierrors.IsNotFound(err)){
fmt.Println("kube-secret not found for execution", executionId) fmt.Println("kube-secret not found for execution", executionId)
return nil, nil return nil, nil
} }
fmt.Println("Error while trying to contact API to get secret kube-secret-" + executionId) fmt.Println("Error while trying to contact API to get secret kube-secret-"+executionId)
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
} }
@@ -407,41 +434,73 @@ func (k *KubernetesService) GetKubeconfigSecret(context context.Context, executi
return data, nil return data, nil
} }
func (k *KubernetesService) DeleteKubeConfigSecret(executionID string) ([]byte, error) { func (k *KubernetesService) DeleteKubeConfigSecret(executionID string) ([]byte, error){
return []byte{}, nil return []byte{}, 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).
DoRaw(ctx) // from https://stackoverflow.com/questions/60764908/how-to-access-kubernetes-crd-using-client-go DoRaw(ctx) // from https://stackoverflow.com/questions/60764908/how-to-access-kubernetes-crd-using-client-go
if err != nil { if err != nil {
fmt.Println("Error from k8s API when getting "+path+" : ", err) fmt.Println("Error from k8s API when getting " + path + " : " , err)
return nil, err return nil,err
} }
return resp, nil return resp, nil
} }
func postCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string, body []byte, params ...map[string]string) ([]byte, error) { func dynamicClientApply(executionId string, typeResource string, resourceDefinition schema.GroupVersionResource, ctx context.Context, object map[string]interface{}) ([]byte, error) {
req := client.RESTClient(). cli, err := NewDynamicClient()
Post(). if err != nil {
AbsPath(path). return nil, errors.New("Could not retrieve dynamic client when creating Admiralty Source : " + err.Error())
Body(body)
for _, param := range params {
for k, v := range param {
req = req.Param(k, v)
}
} }
res, err := cli.Resource(resourceDefinition).
Namespace(executionId).
Apply(ctx,
typeResource + "-" + executionId,
&unstructured.Unstructured{Object: object},
metav1.ApplyOptions{
FieldManager: "kubectl-client-side-apply",
},
)
if err != nil {
fmt.Println("Error from k8s API when applying " + fmt.Sprint(object) + " 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) resp, err := req.DoRaw(ctx)
if err != nil { if err != nil {
fmt.Println("Error from k8s API when posting "+string(body)+" to "+path+" : ", err) fmt.Println("Error from k8s API when posting " + string(body) + " to " + path + " : " , err)
return nil, err return nil,err
} }
return resp, nil return resp, nil
@@ -450,13 +509,13 @@ func postCDRapiKube(client kubernetes.Clientset, ctx context.Context, path strin
// Returns the Kubernetes' Node object corresponding to the executionID if it exists on this host // 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) // 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) { func (k *KubernetesService) GetOneNode(context context.Context,executionID string) (*v1.Node, error) {
res, err := k.Set.CoreV1(). res, err := k.Set.CoreV1().
Nodes(). Nodes().
List( List(
context, context,
metav1.ListOptions{}, metav1.ListOptions{},
) )
if err != nil { if err != nil {
fmt.Println("Error getting the list of nodes from k8s API") fmt.Println("Error getting the list of nodes from k8s API")
fmt.Println(err) fmt.Println(err)
@@ -464,10 +523,10 @@ func (k *KubernetesService) GetOneNode(context context.Context, executionID stri
} }
for _, node := range res.Items { for _, node := range res.Items {
if isNode := strings.Contains(node.Name, "admiralty-"+executionID+"-target-"+executionID+"-"); isNode { if isNode := strings.Contains(node.Name,"admiralty-"+executionID+"-target-"+executionID+"-"); isNode {
return &node, nil return &node, nil
} }
} }
return nil, nil return nil, nil
} }

View File

@@ -4,7 +4,6 @@ import (
"encoding/base64" "encoding/base64"
"oc-datacenter/conf" "oc-datacenter/conf"
_ "oc-datacenter/routers" _ "oc-datacenter/routers"
"os"
oclib "cloud.o-forge.io/core/oc-lib" oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/tools" "cloud.o-forge.io/core/oc-lib/tools"
@@ -21,7 +20,7 @@ func main() {
// Load the right config file // Load the right config file
o := oclib.GetConfLoader() o := oclib.GetConfLoader()
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", "")
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", ""))

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

View File

@@ -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>

View File

@@ -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

View File

@@ -1,559 +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": {
"/": {
"get": {
"tags": [
"oc-datacenter/controllersDatacenterController"
],
"description": "find booking by id\n\u003cbr\u003e",
"operationId": "DatacenterController.GetAll",
"parameters": [
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"type": "string"
}
],
"responses": {
"200": {
"description": "{booking} models.booking"
}
}
}
},
"/admiralty/kubeconfig/{execution}": {
"get": {
"tags": [
"admiralty"
],
"parameters": [
{
"in": "path",
"name": "execution",
"description": "execution id of the workflow",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/admiralty/node/{execution}": {
"get": {
"tags": [
"admiralty"
],
"parameters": [
{
"in": "path",
"name": "execution",
"description": "execution id of the workflow",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/admiralty/secret/{execution}": {
"get": {
"tags": [
"admiralty"
],
"parameters": [
{
"in": "path",
"name": "execution",
"description": "execution id of the workflow",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": ""
}
}
},
"post": {
"tags": [
"admiralty"
],
"parameters": [
{
"in": "path",
"name": "execution",
"description": "execution id of the workflow",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "kubeconfig",
"description": "Kubeconfig to use when creating secret",
"required": true,
"schema": {
"$ref": "#/definitions/controllers.RemoteKubeconfig"
}
}
],
"responses": {
"201": {
"description": ""
}
}
}
},
"/admiralty/source/{execution}": {
"post": {
"tags": [
"admiralty"
],
"description": "Create an Admiralty Source on remote cluster\n\u003cbr\u003e",
"operationId": "AdmiraltyController.CreateSource",
"parameters": [
{
"in": "path",
"name": "execution",
"description": "execution id of the workflow",
"required": true,
"type": "string"
}
],
"responses": {
"201": {
"description": ""
}
}
}
},
"/admiralty/target/{execution}": {
"post": {
"tags": [
"admiralty"
],
"description": "Create an Admiralty Target in the namespace associated to the executionID\n\u003cbr\u003e",
"operationId": "AdmiraltyController.CreateAdmiraltyTarget",
"parameters": [
{
"in": "path",
"name": "execution",
"description": "execution id of the workflow",
"required": true,
"type": "string"
}
],
"responses": {
"201": {
"description": ""
}
}
}
},
"/admiralty/targets": {
"get": {
"tags": [
"admiralty"
],
"description": "find all Admiralty Target\n\u003cbr\u003e",
"operationId": "AdmiraltyController.GetAllTargets",
"responses": {
"200": {
"description": ""
}
}
}
},
"/admiralty/targets/{execution}": {
"get": {
"tags": [
"admiralty"
],
"description": "find one Admiralty Target\n\u003cbr\u003e",
"operationId": "AdmiraltyController.GetOneTarget",
"parameters": [
{
"in": "path",
"name": "id",
"description": "the name of the target to get",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": ""
}
}
}
},
"/booking/": {
"get": {
"tags": [
"booking"
],
"description": "find booking by id\n\u003cbr\u003e",
"operationId": "BookingController.GetAll",
"parameters": [
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"type": "string"
}
],
"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"
},
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"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"
},
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"type": "string"
}
],
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/models.object"
}
}
}
}
},
"/booking/search/execution/{id}": {
"get": {
"tags": [
"booking"
],
"description": "search bookings by execution\n\u003cbr\u003e",
"operationId": "BookingController.ExecutionSearch",
"parameters": [
{
"in": "path",
"name": "id",
"description": "id execution",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"type": "string"
}
],
"responses": {
"200": {
"description": "{workspace} models.workspace"
}
}
}
},
"/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"
},
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"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"
}
}
},
"put": {
"tags": [
"booking"
],
"description": "create computes\n\u003cbr\u003e",
"operationId": "BookingController.Update",
"parameters": [
{
"in": "path",
"name": "id",
"description": "the compute id you want to get",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"description": "The compute content",
"required": true,
"schema": {
"$ref": "#/definitions/models.compute"
}
}
],
"responses": {
"200": {
"description": "{compute} models.compute"
}
}
}
},
"/session/token/{id}/{duration}": {
"get": {
"tags": [
"session"
],
"description": "find booking by id\n\u003cbr\u003e",
"operationId": "SessionController.GetToken",
"parameters": [
{
"in": "path",
"name": "id",
"description": "id of the datacenter",
"type": "string"
},
{
"in": "path",
"name": "duration",
"description": "duration of the token",
"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": ""
}
}
}
},
"/{id}": {
"get": {
"tags": [
"oc-datacenter/controllersDatacenterController"
],
"description": "find booking by id\n\u003cbr\u003e",
"operationId": "DatacenterController.Get",
"parameters": [
{
"in": "path",
"name": "id",
"description": "the id you want to get",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "is_draft",
"description": "draft wished",
"type": "string"
}
],
"responses": {
"200": {
"description": "{booking} models.booking"
}
}
}
}
},
"definitions": {
"controllers.RemoteKubeconfig": {
"title": "RemoteKubeconfig",
"type": "object",
"properties": {
"Data": {
"type": "string"
}
}
},
"models.compute": {
"title": "compute",
"type": "object"
},
"models.object": {
"title": "object",
"type": "object"
}
},
"tags": [
{
"name": "oc-datacenter/controllersDatacenterController",
"description": "Operations about workspace\n"
},
{
"name": "booking",
"description": "Operations about workspace\n"
},
{
"name": "session",
"description": "Operations about session and token management\n"
},
{
"name": "version",
"description": "VersionController operations for Version\n"
},
{
"name": "admiralty",
"description": "Operations about the admiralty objects of the datacenter\n"
}
]
}

View File

@@ -1,399 +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:
/:
get:
tags:
- oc-datacenter/controllersDatacenterController
description: |-
find booking by id
<br>
operationId: DatacenterController.GetAll
parameters:
- in: query
name: is_draft
description: draft wished
type: string
responses:
"200":
description: '{booking} models.booking'
/{id}:
get:
tags:
- oc-datacenter/controllersDatacenterController
description: |-
find booking by id
<br>
operationId: DatacenterController.Get
parameters:
- in: path
name: id
description: the id you want to get
required: true
type: string
- in: query
name: is_draft
description: draft wished
type: string
responses:
"200":
description: '{booking} models.booking'
/admiralty/kubeconfig/{execution}:
get:
tags:
- admiralty
parameters:
- in: path
name: execution
description: execution id of the workflow
required: true
type: string
responses:
"200":
description: ""
/admiralty/node/{execution}:
get:
tags:
- admiralty
parameters:
- in: path
name: execution
description: execution id of the workflow
required: true
type: string
responses:
"200":
description: ""
/admiralty/secret/{execution}:
get:
tags:
- admiralty
parameters:
- in: path
name: execution
description: execution id of the workflow
required: true
type: string
responses:
"200":
description: ""
post:
tags:
- admiralty
parameters:
- in: path
name: execution
description: execution id of the workflow
required: true
type: string
- in: body
name: kubeconfig
description: Kubeconfig to use when creating secret
required: true
schema:
$ref: '#/definitions/controllers.RemoteKubeconfig'
responses:
"201":
description: ""
/admiralty/source/{execution}:
post:
tags:
- admiralty
description: |-
Create an Admiralty Source on remote cluster
<br>
operationId: AdmiraltyController.CreateSource
parameters:
- in: path
name: execution
description: execution id of the workflow
required: true
type: string
responses:
"201":
description: ""
/admiralty/target/{execution}:
post:
tags:
- admiralty
description: |-
Create an Admiralty Target in the namespace associated to the executionID
<br>
operationId: AdmiraltyController.CreateAdmiraltyTarget
parameters:
- in: path
name: execution
description: execution id of the workflow
required: true
type: string
responses:
"201":
description: ""
/admiralty/targets:
get:
tags:
- admiralty
description: |-
find all Admiralty Target
<br>
operationId: AdmiraltyController.GetAllTargets
responses:
"200":
description: ""
/admiralty/targets/{execution}:
get:
tags:
- admiralty
description: |-
find one Admiralty Target
<br>
operationId: AdmiraltyController.GetOneTarget
parameters:
- in: path
name: id
description: the name of the target to get
required: true
type: string
responses:
"200":
description: ""
/booking/:
get:
tags:
- booking
description: |-
find booking by id
<br>
operationId: BookingController.GetAll
parameters:
- in: query
name: is_draft
description: draft wished
type: string
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
- in: query
name: is_draft
description: draft wished
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'
put:
tags:
- booking
description: |-
create computes
<br>
operationId: BookingController.Update
parameters:
- in: path
name: id
description: the compute id you want to get
required: true
type: string
- in: body
name: body
description: The compute content
required: true
schema:
$ref: '#/definitions/models.compute'
responses:
"200":
description: '{compute} models.compute'
/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
- in: query
name: is_draft
description: draft wished
type: string
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
- in: query
name: is_draft
description: draft wished
type: string
responses:
"200":
description: '{workspace} models.workspace'
/booking/search/execution/{id}:
get:
tags:
- booking
description: |-
search bookings by execution
<br>
operationId: BookingController.ExecutionSearch
parameters:
- in: path
name: id
description: id execution
required: true
type: string
- in: query
name: is_draft
description: draft wished
type: string
responses:
"200":
description: '{workspace} models.workspace'
/session/token/{id}/{duration}:
get:
tags:
- session
description: |-
find booking by id
<br>
operationId: SessionController.GetToken
parameters:
- in: path
name: id
description: id of the datacenter
type: string
- in: path
name: duration
description: duration of the token
type: string
responses:
"200":
description: '{booking} models.booking'
/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:
controllers.RemoteKubeconfig:
title: RemoteKubeconfig
type: object
properties:
Data:
type: string
models.compute:
title: compute
type: object
models.object:
title: object
type: object
tags:
- name: oc-datacenter/controllersDatacenterController
description: |
Operations about workspace
- name: booking
description: |
Operations about workspace
- name: session
description: |
Operations about session and token management
- name: version
description: |
VersionController operations for Version
- name: admiralty
description: |
Operations about the admiralty objects of the datacenter