Skip to content

Commit

Permalink
feat: demultiplex reconciliations
Browse files Browse the repository at this point in the history
  • Loading branch information
yyewolf committed Oct 13, 2024
1 parent 29f49c4 commit c97daba
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 1 deletion.
2 changes: 1 addition & 1 deletion doc/openapi.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"openapi":"3.1.0","components":{"schemas":{"HTTPError":{"description":"HTTPError schema","properties":{"detail":{"description":"Human readable error message","nullable":true,"type":"string"},"errors":{"items":{"properties":{"more":{"additionalProperties":{},"type":"object"},"name":{"type":"string"},"reason":{"type":"string"}},"type":"object"},"nullable":true,"type":"array"},"instance":{"nullable":true,"type":"string"},"status":{"description":"HTTP status code","example":403,"nullable":true,"type":"integer"},"title":{"description":"Short title of the error","nullable":true,"type":"string"},"type":{"description":"URL of the error type. Can be used to lookup the error in a documentation","nullable":true,"type":"string"}},"type":"object"},"InstanceStatus":{"description":"InstanceStatus schema","properties":{"endsAt":{"format":"date-time","nullable":true,"type":"string"},"name":{"type":"string"},"servers":{"items":{"properties":{"host":{"type":"string"},"kind":{"type":"string"},"port":{"type":"integer"}},"type":"object"},"nullable":true,"type":"array"},"status":{"type":"string"},"timeout":{"type":"integer"}},"type":"object"},"bool":{"description":"bool schema","type":"boolean"},"unknown-interface":{"description":"unknown-interface schema"}}},"info":{"description":"\nThis is the autogenerated OpenAPI documentation for your [Fuego](https://github.com/go-fuego/fuego) API.\n\nBelow is a Fuego Cheatsheet to help you get started. Don't hesitate to check the [Fuego documentation](https://go-fuego.github.io/fuego) for more details.\n\nHappy coding! 🔥\n\n## Usage\n\n### Route registration\n\n```go\nfunc main() {\n\t// Create a new server\n\ts := fuego.NewServer()\n\n\t// Register some routes\n\tfuego.Post(s, \"/hello\", myController)\n\tfuego.Get(s, \"/myPath\", otherController)\n\tfuego.Put(s, \"/hello\", thirdController)\n\n\tadminRoutes := fuego.Group(s, \"/admin\")\n\tfuego.Use(adminRoutes, myMiddleware) // This middleware (for authentication, etc...) will be available for routes starting by /admin/*, \n\tfuego.Get(adminRoutes, \"/hello\", groupController) // This route will be available at /admin/hello\n\n\t// Start the server\n\ts.Start()\n}\n```\n\n### Basic controller\n\n```go\ntype MyBody struct {\n\tName string `json:\"name\" validate:\"required,max=30\"`\n}\n\ntype MyResponse struct {\n\tAnswer string `json:\"answer\"`\n}\n\nfunc hello(ctx *fuego.ContextWithBody[MyBody]) (*MyResponse, error) {\n\tbody, err := ctx.Body()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn \u0026MyResponse{Answer: \"Hello \" + body.Name}, nil\n}\n```\n\n### Add more details to the route\n\n```go\nfuego.Get(s, \"/hello\", myController).\n\tDescription(\"This is a route that says hello\").\n\tSummary(\"Say hello\").\n```\n","title":"OpenAPI","version":"0.0.1"},"paths":{"/api/v1/{challengeId}/{instanceId}":{"delete":{"description":"controller: `instancer/web.SetupServer.DeleteInstance.func4`\n\n---\n\n","operationId":"DELETE_/api/v1/:challengeId/:instanceId","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}},"application/xml":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func4"},"get":{"description":"controller: `instancer/web.SetupServer.GetInstance.func2`\n\n---\n\n","operationId":"GET_/api/v1/:challengeId/:instanceId","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}},"application/xml":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func2"},"post":{"description":"controller: `instancer/web.SetupServer.CreateInstance.func3`\n\n---\n\n","operationId":"POST_/api/v1/:challengeId/:instanceId","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}},"application/xml":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func3"}},"/api/v1/{challengeId}/{instanceId}/is_solved":{"get":{"description":"controller: `instancer/web.SetupServer.IsInstanceSolved.func1`\n\n---\n\n","operationId":"GET_/api/v1/:challengeId/:instanceId/is_solved","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/bool"}},"application/xml":{"schema":{"$ref":"#/components/schemas/bool"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func1"}}},"servers":[{"description":"local server","url":"http://localhost:9999"}]}
{"openapi":"3.1.0","components":{"schemas":{"HTTPError":{"description":"HTTPError schema","properties":{"detail":{"description":"Human readable error message","nullable":true,"type":"string"},"errors":{"items":{"properties":{"more":{"additionalProperties":{},"type":"object"},"name":{"type":"string"},"reason":{"type":"string"}},"type":"object"},"nullable":true,"type":"array"},"instance":{"nullable":true,"type":"string"},"status":{"description":"HTTP status code","example":403,"nullable":true,"type":"integer"},"title":{"description":"Short title of the error","nullable":true,"type":"string"},"type":{"description":"URL of the error type. Can be used to lookup the error in a documentation","nullable":true,"type":"string"}},"type":"object"},"InstanceStatus":{"description":"InstanceStatus schema","properties":{"endsAt":{"format":"date-time","nullable":true,"type":"string"},"name":{"type":"string"},"servers":{"items":{"properties":{"description":{"type":"string"},"host":{"type":"string"},"instructions":{"type":"string"},"kind":{"type":"string"},"port":{"type":"integer"}},"type":"object"},"nullable":true,"type":"array"},"status":{"type":"string"},"timeout":{"type":"integer"}},"type":"object"},"bool":{"description":"bool schema","type":"boolean"},"unknown-interface":{"description":"unknown-interface schema"}}},"info":{"description":"\nThis is the autogenerated OpenAPI documentation for your [Fuego](https://github.com/go-fuego/fuego) API.\n\nBelow is a Fuego Cheatsheet to help you get started. Don't hesitate to check the [Fuego documentation](https://go-fuego.github.io/fuego) for more details.\n\nHappy coding! 🔥\n\n## Usage\n\n### Route registration\n\n```go\nfunc main() {\n\t// Create a new server\n\ts := fuego.NewServer()\n\n\t// Register some routes\n\tfuego.Post(s, \"/hello\", myController)\n\tfuego.Get(s, \"/myPath\", otherController)\n\tfuego.Put(s, \"/hello\", thirdController)\n\n\tadminRoutes := fuego.Group(s, \"/admin\")\n\tfuego.Use(adminRoutes, myMiddleware) // This middleware (for authentication, etc...) will be available for routes starting by /admin/*, \n\tfuego.Get(adminRoutes, \"/hello\", groupController) // This route will be available at /admin/hello\n\n\t// Start the server\n\ts.Start()\n}\n```\n\n### Basic controller\n\n```go\ntype MyBody struct {\n\tName string `json:\"name\" validate:\"required,max=30\"`\n}\n\ntype MyResponse struct {\n\tAnswer string `json:\"answer\"`\n}\n\nfunc hello(ctx *fuego.ContextWithBody[MyBody]) (*MyResponse, error) {\n\tbody, err := ctx.Body()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn \u0026MyResponse{Answer: \"Hello \" + body.Name}, nil\n}\n```\n\n### Add more details to the route\n\n```go\nfuego.Get(s, \"/hello\", myController).\n\tDescription(\"This is a route that says hello\").\n\tSummary(\"Say hello\").\n```\n","title":"OpenAPI","version":"0.0.1"},"paths":{"/api/v1/{challengeId}/{instanceId}":{"delete":{"description":"controller: `instancer/web.SetupServer.DeleteInstance.func4`\n\n---\n\n","operationId":"DELETE_/api/v1/:challengeId/:instanceId","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}},"application/xml":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func4"},"get":{"description":"controller: `instancer/web.SetupServer.GetInstance.func2`\n\n---\n\n","operationId":"GET_/api/v1/:challengeId/:instanceId","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}},"application/xml":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func2"},"post":{"description":"controller: `instancer/web.SetupServer.CreateInstance.func3`\n\n---\n\n","operationId":"POST_/api/v1/:challengeId/:instanceId","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}},"application/xml":{"schema":{"$ref":"#/components/schemas/InstanceStatus"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func3"}},"/api/v1/{challengeId}/{instanceId}/is_solved":{"get":{"description":"controller: `instancer/web.SetupServer.IsInstanceSolved.func1`\n\n---\n\n","operationId":"GET_/api/v1/:challengeId/:instanceId/is_solved","parameters":[{"in":"path","name":"challengeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"instanceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/bool"}},"application/xml":{"schema":{"$ref":"#/components/schemas/bool"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Bad Request _(validation or deserialization error)_"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPError"}}},"description":"Internal Server Error _(panics)_"},"default":{"description":""}},"summary":"func1"}}},"servers":[{"description":"local server","url":"http://localhost:9999"}]}
6 changes: 6 additions & 0 deletions internal/controllers/k8s_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
v1 "instancer/api/v1"
"instancer/internal/ctf"
"strconv"
"sync"
"time"

core "k8s.io/api/core/v1"
Expand Down Expand Up @@ -35,6 +36,8 @@ type InstancierReconciler struct {
tasks map[string]chrono.ScheduledTask
}

var reconcilerMutex sync.Mutex

// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;create;delete;watch
// +kubebuilder:rbac:groups="",resources=services,verbs=create;delete;watch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;create
Expand All @@ -46,6 +49,9 @@ type InstancierReconciler struct {
// +kubebuilder:rbac:groups=i.4ts.fr,resources=instancedchallenges,verbs=get;list;watch
// +kubebuilder:rbac:groups=i.4ts.fr,resources=oracleinstancedchallenges,verbs=get;list;watch
func (r *InstancierReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
reconcilerMutex.Lock()
defer reconcilerMutex.Unlock()

_ = log.FromContext(ctx)

// Init map if not init
Expand Down
3 changes: 3 additions & 0 deletions internal/ctf/ctfd.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

type Client struct {
*ctfd.Client

Queue chan *ctfd.Challenge
}

func New() *Client {
Expand All @@ -22,5 +24,6 @@ func New() *Client {
client := ctfd.NewClient(c.CTFd.URL, nonce, session, c.CTFd.Token)
return &Client{
Client: client,
Queue: make(chan *ctfd.Challenge),
}
}

0 comments on commit c97daba

Please sign in to comment.