Skip to content

Commit 67eaa46

Browse files
committed
add team instance list endpoint
1 parent e2158c1 commit 67eaa46

File tree

4 files changed

+71
-1
lines changed

4 files changed

+71
-1
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# ubcctf/instanced
22

3+
currently Jank As Hell.
4+
35
Manages challenge instances on-demand.
46

57
`instanced` runs in the cluster and exposes an HTTP API which is used to request instances.
8+
Challenge templates are added in the form of CRDs. Example format is in this repository.
9+
`instanced` must be restarted every time new CRDs are applied.
10+
11+
Instances created are kept track of in a local sqlite database. The instancer periodically scans the database for expired instances and deletes them.
12+
613

714
- GET `/instances` - get list of active instances
15+
- GET `/challenges?team=$ID` - get list of available challenges and instance states for specific team
816
- POST `/instances?chal=$CHALLNAME&team=$ID` - provision an instance for specific challenge and team
917
- DELETE `/instances?id=$ID` - delete challenge with id
1018

11-
Authenticate with `Bearer token`

db.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,33 @@ func (in *Instancer) ReadInstanceRecords() ([]InstanceRecord, error) {
109109
err = rows.Err()
110110
return records, err
111111
}
112+
113+
func (in *Instancer) ReadInstanceRecordsTeam(teamID string) ([]InstanceRecord, error) {
114+
if in.db == nil {
115+
return nil, errors.New("db not initialized")
116+
}
117+
stmt, err := in.db.Prepare("SELECT id, challenge, team, expiry FROM instances WHERE team = ?")
118+
if err != nil {
119+
return nil, err
120+
}
121+
defer stmt.Close()
122+
123+
rows, err := stmt.Query(teamID)
124+
if err != nil {
125+
return nil, err
126+
}
127+
defer rows.Close()
128+
records := make([]InstanceRecord, 0)
129+
for rows.Next() {
130+
record := InstanceRecord{}
131+
var t int64
132+
err = rows.Scan(&record.Id, &record.Challenge, &record.TeamID, &t)
133+
if err != nil {
134+
return records, err
135+
}
136+
record.Expiry = time.Unix(t, 0)
137+
records = append(records, record)
138+
}
139+
err = rows.Err()
140+
return records, err
141+
}

instancer.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,26 @@ func (in *Instancer) CreateInstance(challenge, team string) (InstanceRecord, err
171171
return rec, nil
172172
}
173173

174+
func (in *Instancer) GetTeamChallengeStates(teamID string) ([]InstanceRecord, error) {
175+
instances, err := in.ReadInstanceRecordsTeam(teamID)
176+
if err != nil {
177+
return nil, err
178+
}
179+
for k := range in.challengeObjs {
180+
active := false
181+
for _, v := range instances {
182+
if v.Challenge == k {
183+
active = true
184+
break
185+
}
186+
}
187+
if !active {
188+
instances = append(instances, InstanceRecord{Expiry: time.Unix(0, 0), Challenge: k, TeamID: teamID})
189+
}
190+
}
191+
return instances, nil
192+
}
193+
174194
func (in *Instancer) Start() error {
175195
log := in.log.With().Str("component", "instanced").Logger()
176196
log.Info().Msg("starting webserver...")

webserver.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ func (in *Instancer) registerEndpoints() {
1717
in.echo.POST("/instances", in.handleInstanceCreate)
1818

1919
in.echo.DELETE("/instances", in.handleInstanceDelete)
20+
21+
in.echo.GET("/challenges", in.handleInstanceListTeam)
2022
}
2123

2224
type InstancesResponse struct {
@@ -82,3 +84,14 @@ func (in *Instancer) handleInstanceList(c echo.Context) error {
8284
// todo: properly marshal records
8385
return c.JSON(http.StatusOK, records)
8486
}
87+
88+
func (in *Instancer) handleInstanceListTeam(c echo.Context) error {
89+
teamID := c.QueryParam("team")
90+
records, err := in.GetTeamChallengeStates(teamID)
91+
if err != nil {
92+
c.Logger().Errorf("request failed: %v", err)
93+
return c.JSON(http.StatusInternalServerError, "request failed")
94+
}
95+
// todo: properly marshal records
96+
return c.JSON(http.StatusOK, records)
97+
}

0 commit comments

Comments
 (0)