Split backend service into checker and generator
Both are linked through a unix socket.
This commit is contained in:
parent
f755d7c998
commit
ed091e761c
@ -1,7 +1,8 @@
|
|||||||
admin/admin
|
admin/admin
|
||||||
backend/backend
|
checker/checker
|
||||||
dashboard/dashboard
|
dashboard/dashboard
|
||||||
evdist/evdist
|
evdist/evdist
|
||||||
|
generator/generator
|
||||||
receiver/receiver
|
receiver/receiver
|
||||||
repochecker/repochecker
|
repochecker/repochecker
|
||||||
frontend/fic/build
|
frontend/fic/build
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
image: nemunaire/fic-backend:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
image: nemunaire/fic-checker:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
||||||
{{#if build.tags}}
|
{{#if build.tags}}
|
||||||
tags:
|
tags:
|
||||||
{{#each build.tags}}
|
{{#each build.tags}}
|
||||||
@ -6,16 +6,16 @@ tags:
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
manifests:
|
manifests:
|
||||||
- image: nemunaire/fic-backend:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
- image: nemunaire/fic-checker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
||||||
platform:
|
platform:
|
||||||
architecture: amd64
|
architecture: amd64
|
||||||
os: linux
|
os: linux
|
||||||
- image: nemunaire/fic-backend:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
- image: nemunaire/fic-checker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
||||||
platform:
|
platform:
|
||||||
architecture: arm64
|
architecture: arm64
|
||||||
os: linux
|
os: linux
|
||||||
variant: v8
|
variant: v8
|
||||||
- image: nemunaire/fic-backend:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
|
- image: nemunaire/fic-checker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
|
||||||
platform:
|
platform:
|
||||||
architecture: arm
|
architecture: arm
|
||||||
os: linux
|
os: linux
|
22
.drone-manifest-fic-generator.yml
Normal file
22
.drone-manifest-fic-generator.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
image: nemunaire/fic-generator:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
||||||
|
{{#if build.tags}}
|
||||||
|
tags:
|
||||||
|
{{#each build.tags}}
|
||||||
|
- {{this}}
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
manifests:
|
||||||
|
- image: nemunaire/fic-generator:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
||||||
|
platform:
|
||||||
|
architecture: amd64
|
||||||
|
os: linux
|
||||||
|
- image: nemunaire/fic-generator:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
||||||
|
platform:
|
||||||
|
architecture: arm64
|
||||||
|
os: linux
|
||||||
|
variant: v8
|
||||||
|
- image: nemunaire/fic-generator:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
|
||||||
|
platform:
|
||||||
|
architecture: arm
|
||||||
|
os: linux
|
||||||
|
variant: v7
|
87
.drone.yml
87
.drone.yml
@ -17,8 +17,9 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- apk --no-cache add git
|
- apk --no-cache add git
|
||||||
- go get -v -d srs.epita.fr/fic-server/admin
|
- go get -v -d srs.epita.fr/fic-server/admin
|
||||||
- go get -v -d srs.epita.fr/fic-server/backend
|
- go get -v -d srs.epita.fr/fic-server/checker
|
||||||
- go get -v -d srs.epita.fr/fic-server/evdist
|
- go get -v -d srs.epita.fr/fic-server/evdist
|
||||||
|
- go get -v -d srs.epita.fr/fic-server/generator
|
||||||
- go get -v -d srs.epita.fr/fic-server/receiver
|
- go get -v -d srs.epita.fr/fic-server/receiver
|
||||||
- go get -v -d srs.epita.fr/fic-server/dashboard
|
- go get -v -d srs.epita.fr/fic-server/dashboard
|
||||||
- go get -v -d srs.epita.fr/fic-server/repochecker
|
- go get -v -d srs.epita.fr/fic-server/repochecker
|
||||||
@ -48,8 +49,9 @@ steps:
|
|||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/admin/sync
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/admin/sync
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/admin/pki
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/admin/pki
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/admin
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/admin
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/backend
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/checker
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/evdist
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/evdist
|
||||||
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/generator
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/receiver
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/receiver
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/dashboard
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/dashboard
|
||||||
- go vet -v -buildvcs=false srs.epita.fr/fic-server/repochecker
|
- go vet -v -buildvcs=false srs.epita.fr/fic-server/repochecker
|
||||||
@ -70,10 +72,10 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
- name: build backend
|
- name: build checker
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
commands:
|
commands:
|
||||||
- go build -v -buildvcs=false -o deploy/backend-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} srs.epita.fr/fic-server/backend
|
- go build -v -buildvcs=false -o deploy/checker-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} srs.epita.fr/fic-server/checker
|
||||||
environment:
|
environment:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@ -84,6 +86,13 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
|
- name: build generator
|
||||||
|
image: golang:alpine
|
||||||
|
commands:
|
||||||
|
- go build -v -buildvcs=false -o deploy/generator-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} srs.epita.fr/fic-server/generator
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
- name: build receiver
|
- name: build receiver
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
commands:
|
commands:
|
||||||
@ -176,17 +185,17 @@ steps:
|
|||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
- name: docker backend
|
- name: docker checker
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
username:
|
username:
|
||||||
from_secret: docker_username
|
from_secret: docker_username
|
||||||
password:
|
password:
|
||||||
from_secret: docker_password
|
from_secret: docker_password
|
||||||
repo: nemunaire/fic-backend
|
repo: nemunaire/fic-checker
|
||||||
auto_tag: true
|
auto_tag: true
|
||||||
auto_tag_suffix: ${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
auto_tag_suffix: ${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
||||||
dockerfile: Dockerfile-backend
|
dockerfile: Dockerfile-checker
|
||||||
when:
|
when:
|
||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
@ -206,6 +215,20 @@ steps:
|
|||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
|
- name: docker generator
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
repo: nemunaire/fic-generator
|
||||||
|
auto_tag: true
|
||||||
|
auto_tag_suffix: ${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
||||||
|
dockerfile: Dockerfile-generator
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- master
|
||||||
- name: docker receiver
|
- name: docker receiver
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
@ -351,8 +374,9 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- apk --no-cache add git
|
- apk --no-cache add git
|
||||||
- go get -v -d srs.epita.fr/fic-server/admin
|
- go get -v -d srs.epita.fr/fic-server/admin
|
||||||
- go get -v -d srs.epita.fr/fic-server/backend
|
- go get -v -d srs.epita.fr/fic-server/checker
|
||||||
- go get -v -d srs.epita.fr/fic-server/evdist
|
- go get -v -d srs.epita.fr/fic-server/evdist
|
||||||
|
- go get -v -d srs.epita.fr/fic-server/generator
|
||||||
- go get -v -d srs.epita.fr/fic-server/receiver
|
- go get -v -d srs.epita.fr/fic-server/receiver
|
||||||
- go get -v -d srs.epita.fr/fic-server/dashboard
|
- go get -v -d srs.epita.fr/fic-server/dashboard
|
||||||
|
|
||||||
@ -364,10 +388,10 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
- name: build backend
|
- name: build checker
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
commands:
|
commands:
|
||||||
- go build -v -buildvcs=false -o deploy/backend-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} srs.epita.fr/fic-server/backend
|
- go build -v -buildvcs=false -o deploy/checker-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} srs.epita.fr/fic-server/checker
|
||||||
environment:
|
environment:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@ -378,6 +402,13 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
|
- name: build generator
|
||||||
|
image: golang:alpine
|
||||||
|
commands:
|
||||||
|
- go build -v -buildvcs=false -o deploy/generator-${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH} srs.epita.fr/fic-server/generator
|
||||||
|
environment:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
- name: build receiver
|
- name: build receiver
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
commands:
|
commands:
|
||||||
@ -472,17 +503,17 @@ steps:
|
|||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
- name: docker backend
|
- name: docker checker
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
username:
|
username:
|
||||||
from_secret: docker_username
|
from_secret: docker_username
|
||||||
password:
|
password:
|
||||||
from_secret: docker_password
|
from_secret: docker_password
|
||||||
repo: nemunaire/fic-backend
|
repo: nemunaire/fic-checker
|
||||||
auto_tag: true
|
auto_tag: true
|
||||||
auto_tag_suffix: ${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
auto_tag_suffix: ${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
||||||
dockerfile: Dockerfile-backend
|
dockerfile: Dockerfile-checker
|
||||||
when:
|
when:
|
||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
@ -502,6 +533,21 @@ steps:
|
|||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
|
- name: docker generator
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
repo: nemunaire/fic-generator
|
||||||
|
auto_tag: true
|
||||||
|
auto_tag_suffix: ${DRONE_STAGE_OS}-${DRONE_STAGE_ARCH}
|
||||||
|
dockerfile: Dockerfile-generator
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- master
|
||||||
|
|
||||||
- name: docker receiver
|
- name: docker receiver
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
@ -598,12 +644,12 @@ steps:
|
|||||||
password:
|
password:
|
||||||
from_secret: docker_password
|
from_secret: docker_password
|
||||||
|
|
||||||
- name: publish backend
|
- name: publish checker
|
||||||
image: plugins/manifest
|
image: plugins/manifest
|
||||||
settings:
|
settings:
|
||||||
auto_tag: true
|
auto_tag: true
|
||||||
ignore_missing: true
|
ignore_missing: true
|
||||||
spec: .drone-manifest-fic-backend.yml
|
spec: .drone-manifest-fic-checker.yml
|
||||||
username:
|
username:
|
||||||
from_secret: docker_username
|
from_secret: docker_username
|
||||||
password:
|
password:
|
||||||
@ -620,6 +666,17 @@ steps:
|
|||||||
password:
|
password:
|
||||||
from_secret: docker_password
|
from_secret: docker_password
|
||||||
|
|
||||||
|
- name: publish generator
|
||||||
|
image: plugins/manifest
|
||||||
|
settings:
|
||||||
|
auto_tag: true
|
||||||
|
ignore_missing: true
|
||||||
|
spec: .drone-manifest-fic-generator.yml
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
|
||||||
- name: publish receiver
|
- name: publish receiver
|
||||||
image: plugins/manifest
|
image: plugins/manifest
|
||||||
settings:
|
settings:
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
FROM golang:1-alpine as gobuild
|
|
||||||
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
|
|
||||||
WORKDIR /go/src/srs.epita.fr/fic-server/
|
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
|
||||||
COPY settings settings/
|
|
||||||
COPY libfic ./libfic/
|
|
||||||
COPY backend ./backend/
|
|
||||||
|
|
||||||
RUN go get -d -v ./backend && \
|
|
||||||
go build -v -buildvcs=false -o backend/backend ./backend
|
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.18
|
|
||||||
|
|
||||||
WORKDIR /srv
|
|
||||||
|
|
||||||
ENTRYPOINT ["/srv/backend"]
|
|
||||||
|
|
||||||
COPY --from=gobuild /go/src/srs.epita.fr/fic-server/backend/backend /srv/backend
|
|
22
Dockerfile-checker
Normal file
22
Dockerfile-checker
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
FROM golang:1-alpine as gobuild
|
||||||
|
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
|
WORKDIR /go/src/srs.epita.fr/fic-server/
|
||||||
|
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
COPY settings settings/
|
||||||
|
COPY libfic ./libfic/
|
||||||
|
COPY checker ./checker/
|
||||||
|
|
||||||
|
RUN go get -d -v ./checker && \
|
||||||
|
go build -v -buildvcs=false -o checker/checker ./checker
|
||||||
|
|
||||||
|
|
||||||
|
FROM alpine:3.18
|
||||||
|
|
||||||
|
WORKDIR /srv
|
||||||
|
|
||||||
|
ENTRYPOINT ["/srv/checker"]
|
||||||
|
|
||||||
|
COPY --from=gobuild /go/src/srs.epita.fr/fic-server/checker/checker /srv/checker
|
22
Dockerfile-generator
Normal file
22
Dockerfile-generator
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
FROM golang:1-alpine as gobuild
|
||||||
|
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
|
WORKDIR /go/src/srs.epita.fr/fic-server/
|
||||||
|
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
COPY settings settings/
|
||||||
|
COPY libfic ./libfic/
|
||||||
|
COPY generator ./generator/
|
||||||
|
|
||||||
|
RUN go get -d -v ./generator && \
|
||||||
|
go build -v -buildvcs=false -o generator/generator ./generator
|
||||||
|
|
||||||
|
|
||||||
|
FROM alpine:3.18
|
||||||
|
|
||||||
|
WORKDIR /srv
|
||||||
|
|
||||||
|
ENTRYPOINT ["/srv/generator"]
|
||||||
|
|
||||||
|
COPY --from=gobuild /go/src/srs.epita.fr/fic-server/generator/generator /srv/generator
|
@ -13,7 +13,7 @@ FROM nginx:stable-alpine
|
|||||||
|
|
||||||
ENV FIC_BASEURL=/ \
|
ENV FIC_BASEURL=/ \
|
||||||
HOST_RECEIVER=receiver:8080 HOST_ADMIN=admin:8081 HOST_DASHBOARD=dashboard:8082 HOST_QA=qa:8083 \
|
HOST_RECEIVER=receiver:8080 HOST_ADMIN=admin:8081 HOST_DASHBOARD=dashboard:8082 HOST_QA=qa:8083 \
|
||||||
PATH_FILES=/srv/FILES PATH_STARTINGBLOCK=/srv/STARTINGBLOCK PATH_STATIC=/srv/htdocs-frontend PATH_SETTINGS=/srv/SETTINGSDIST PATH_SYNC=/srv/SYNC PATH_TEAMS=/srv/TEAMS
|
PATH_FILES=/srv/FILES PATH_STARTINGBLOCK=/srv/STARTINGBLOCK PATH_STATIC=/srv/htdocs-frontend PATH_SETTINGS=/srv/SETTINGSDIST PATH_TEAMS=/srv/TEAMS
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
|
@ -11,13 +11,14 @@ micro-services :
|
|||||||
|
|
||||||
- `admin` is the web interface and API used to control the challenge
|
- `admin` is the web interface and API used to control the challenge
|
||||||
and doing synchronization.
|
and doing synchronization.
|
||||||
- `backend` is an inotify reacting service that handles submissions
|
- `checker` is an inotify reacting service that handles submissions
|
||||||
checking and team's files generation.
|
checking.
|
||||||
- `dashboard` is a public interface to explain and follow the
|
- `dashboard` is a public interface to explain and follow the
|
||||||
conquest, aims to animate the challenge for visitors.
|
conquest, aims to animate the challenge for visitors.
|
||||||
- `evdist` is an inotify reacting service that handles settings
|
- `evdist` is an inotify reacting service that handles settings
|
||||||
changes during the challenge (eg. a 30 minutes event where hints are
|
changes during the challenge (eg. a 30 minutes event where hints are
|
||||||
free, ...).
|
free, ...).
|
||||||
|
- `generator` takes care of global and team's files generation.
|
||||||
- `qa` is an interface dedicated to challenge development, it stores
|
- `qa` is an interface dedicated to challenge development, it stores
|
||||||
reports to be treated by challenges creators.
|
reports to be treated by challenges creators.
|
||||||
- `receiver` is only responsible for receiving submissions. It is the
|
- `receiver` is only responsible for receiving submissions. It is the
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
@ -15,6 +18,8 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var GeneratorSocket string
|
||||||
|
|
||||||
func declareClaimsRoutes(router *gin.RouterGroup) {
|
func declareClaimsRoutes(router *gin.RouterGroup) {
|
||||||
// Tasks
|
// Tasks
|
||||||
router.GET("/claims", getClaims)
|
router.GET("/claims", getClaims)
|
||||||
@ -287,12 +292,44 @@ func clearClaims(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateTeamIssuesFile(team fic.Team) error {
|
func generateTeamIssuesFile(team fic.Team) error {
|
||||||
if my, err := team.MyIssueFile(); err != nil {
|
if GeneratorSocket == "" {
|
||||||
return fmt.Errorf("Unable to generate issue FILE (tid=%d): %w", team.Id, err)
|
if my, err := team.MyIssueFile(); err != nil {
|
||||||
} else if j, err := json.Marshal(my); err != nil {
|
return fmt.Errorf("Unable to generate issue FILE (tid=%d): %w", team.Id, err)
|
||||||
return fmt.Errorf("Unable to encode issues' file JSON: %w", err)
|
} else if j, err := json.Marshal(my); err != nil {
|
||||||
} else if err = ioutil.WriteFile(path.Join(TeamsDir, fmt.Sprintf("%d", team.Id), "issues.json"), j, 0644); err != nil {
|
return fmt.Errorf("Unable to encode issues' file JSON: %w", err)
|
||||||
return fmt.Errorf("Unable to write issues' file: %w", err)
|
} else if err = ioutil.WriteFile(path.Join(TeamsDir, fmt.Sprintf("%d", team.Id), "issues.json"), j, 0644); err != nil {
|
||||||
|
return fmt.Errorf("Unable to write issues' file: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf, err := json.Marshal(fic.GenStruct{Type: fic.GenTeamIssues, TeamId: team.Id})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Something is wrong with JSON encoder: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sockType := "unix"
|
||||||
|
if strings.Contains(GeneratorSocket, ":") {
|
||||||
|
sockType = "tcp"
|
||||||
|
}
|
||||||
|
|
||||||
|
socket, err := net.Dial(sockType, GeneratorSocket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer socket.Close()
|
||||||
|
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: func(network, addr string) (net.Conn, error) {
|
||||||
|
return socket, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := httpClient.Post("http://localhost/enqueue", "application/json", bytes.NewReader(buf))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to enqueue new generation event: %w", err)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,7 @@ func main() {
|
|||||||
flag.StringVar(&api.DashboardDir, "dashbord", "./DASHBOARD", "Base directory where save public JSON files")
|
flag.StringVar(&api.DashboardDir, "dashbord", "./DASHBOARD", "Base directory where save public JSON files")
|
||||||
flag.StringVar(&settings.SettingsDir, "settings", settings.SettingsDir, "Base directory where load and save settings")
|
flag.StringVar(&settings.SettingsDir, "settings", settings.SettingsDir, "Base directory where load and save settings")
|
||||||
flag.StringVar(&fic.FilesDir, "files", fic.FilesDir, "Base directory where found challenges files, local part")
|
flag.StringVar(&fic.FilesDir, "files", fic.FilesDir, "Base directory where found challenges files, local part")
|
||||||
|
flag.StringVar(&api.GeneratorSocket, "generator", "./GENERATOR/generator.socket", "Path to the generator socket (used to trigger issues.json generations, use an empty string to generate locally)")
|
||||||
flag.StringVar(&localImporterDirectory, "localimport", localImporterDirectory,
|
flag.StringVar(&localImporterDirectory, "localimport", localImporterDirectory,
|
||||||
"Base directory where found challenges files to import, local part")
|
"Base directory where found challenges files to import, local part")
|
||||||
flag.BoolVar(&localImporterSymlink, "localimportsymlink", localImporterSymlink,
|
flag.BoolVar(&localImporterSymlink, "localimportsymlink", localImporterSymlink,
|
||||||
|
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
backend
|
|
1
checker/.gitignore
vendored
Normal file
1
checker/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
checker
|
@ -45,7 +45,7 @@ func treatWantChoices(pathname string, team *fic.Team) {
|
|||||||
} else if err = team.DisplayChoices(flag); err != nil {
|
} else if err = team.DisplayChoices(flag); err != nil {
|
||||||
log.Printf("%s [ERR] %s\n", id, err)
|
log.Printf("%s [ERR] %s\n", id, err)
|
||||||
} else {
|
} else {
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
if err = os.Remove(pathname); err != nil {
|
if err = os.Remove(pathname); err != nil {
|
||||||
log.Printf("%s [ERR] %s\n", id, err)
|
log.Printf("%s [ERR] %s\n", id, err)
|
||||||
}
|
}
|
52
checker/generation.go
Normal file
52
checker/generation.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var generatorSocket string
|
||||||
|
|
||||||
|
func appendGenQueue(gs fic.GenStruct) error {
|
||||||
|
buf, err := json.Marshal(gs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Something is wrong with JSON encoder: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sockType := "unix"
|
||||||
|
if strings.Contains(generatorSocket, ":") {
|
||||||
|
sockType = "tcp"
|
||||||
|
}
|
||||||
|
|
||||||
|
socket, err := net.Dial(sockType, generatorSocket)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to contact generator at: %s, retring in 1 second", generatorSocket)
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
return appendGenQueue(gs)
|
||||||
|
}
|
||||||
|
defer socket.Close()
|
||||||
|
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: func(network, addr string) (net.Conn, error) {
|
||||||
|
return socket, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := httpClient.Post("http://localhost/enqueue", "application/json", bytes.NewReader(buf))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to enqueue new generation event: %w", err)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -56,8 +56,8 @@ func treatOpeningHint(pathname string, team *fic.Team) {
|
|||||||
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
appendGenQueue(genStruct{Type: GenEvents})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenEvents})
|
||||||
if err = os.Remove(pathname); err != nil {
|
if err = os.Remove(pathname); err != nil {
|
||||||
log.Printf("%s [ERR] %s\n", id, err)
|
log.Printf("%s [ERR] %s\n", id, err)
|
||||||
}
|
}
|
@ -60,7 +60,7 @@ func treatIssue(pathname string, team *fic.Team) {
|
|||||||
if err = os.Remove(pathname); err != nil {
|
if err = os.Remove(pathname); err != nil {
|
||||||
log.Printf("%s [ERR] %s\n", id, err)
|
log.Printf("%s [ERR] %s\n", id, err)
|
||||||
}
|
}
|
||||||
genTeamIssuesFile(team)
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeamIssues, TeamId: team.Id})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var exercice *fic.Exercice = nil
|
var exercice *fic.Exercice = nil
|
||||||
@ -85,6 +85,6 @@ func treatIssue(pathname string, team *fic.Team) {
|
|||||||
log.Printf("%s [ERR] %s\n", id, err)
|
log.Printf("%s [ERR] %s\n", id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
genTeamIssuesFile(team)
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeamIssues, TeamId: team.Id})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -75,53 +75,29 @@ func reloadSettings(config *settings.Settings) {
|
|||||||
fic.WChoiceCoefficient = config.WChoiceCurCoefficient
|
fic.WChoiceCoefficient = config.WChoiceCurCoefficient
|
||||||
fic.ExerciceCurrentCoefficient = config.ExerciceCurCoefficient
|
fic.ExerciceCurrentCoefficient = config.ExerciceCurCoefficient
|
||||||
ChStarted = config.Start.Unix() > 0 && time.Since(config.Start) >= 0
|
ChStarted = config.Start.Unix() > 0 && time.Since(config.Start) >= 0
|
||||||
if lastRegeneration != config.Generation || fic.PartialValidation != config.PartialValidation || fic.UnlockedChallengeDepth != config.UnlockedChallengeDepth || fic.UnlockedChallengeUpTo != config.UnlockedChallengeUpTo || fic.DisplayAllFlags != config.DisplayAllFlags || fic.FirstBlood != config.FirstBlood || fic.SubmissionCostBase != config.SubmissionCostBase || fic.SubmissionUniqueness != config.SubmissionUniqueness || fic.DiscountedFactor != config.DiscountedFactor {
|
fic.PartialValidation = config.PartialValidation
|
||||||
fic.PartialValidation = config.PartialValidation
|
fic.UnlockedChallengeDepth = config.UnlockedChallengeDepth
|
||||||
fic.UnlockedChallengeDepth = config.UnlockedChallengeDepth
|
fic.UnlockedChallengeUpTo = config.UnlockedChallengeUpTo
|
||||||
fic.UnlockedChallengeUpTo = config.UnlockedChallengeUpTo
|
fic.DisplayAllFlags = config.DisplayAllFlags
|
||||||
fic.DisplayAllFlags = config.DisplayAllFlags
|
|
||||||
|
|
||||||
fic.FirstBlood = config.FirstBlood
|
fic.FirstBlood = config.FirstBlood
|
||||||
fic.SubmissionCostBase = config.SubmissionCostBase
|
fic.SubmissionCostBase = config.SubmissionCostBase
|
||||||
fic.SubmissionUniqueness = config.SubmissionUniqueness
|
fic.SubmissionUniqueness = config.SubmissionUniqueness
|
||||||
fic.GlobalScoreCoefficient = config.GlobalScoreCoefficient
|
fic.GlobalScoreCoefficient = config.GlobalScoreCoefficient
|
||||||
fic.CountOnlyNotGoodTries = config.CountOnlyNotGoodTries
|
fic.CountOnlyNotGoodTries = config.CountOnlyNotGoodTries
|
||||||
fic.DiscountedFactor = config.DiscountedFactor
|
fic.DiscountedFactor = config.DiscountedFactor
|
||||||
|
|
||||||
if !skipInitialGeneration {
|
|
||||||
log.Println("Generating files...")
|
|
||||||
go func() {
|
|
||||||
genAll()
|
|
||||||
log.Println("Full generation done")
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
skipInitialGeneration = false
|
|
||||||
log.Println("Regeneration skipped by option.")
|
|
||||||
}
|
|
||||||
lastRegeneration = config.Generation
|
|
||||||
} else {
|
|
||||||
log.Println("No change found. Skipping regeneration.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if v, exists := os.LookupEnv("FIC_BASEURL"); exists {
|
|
||||||
fic.FilesDir = v + "files"
|
|
||||||
} else {
|
|
||||||
fic.FilesDir = "/files"
|
|
||||||
}
|
|
||||||
|
|
||||||
var dsn = flag.String("dsn", fic.DSNGenerator(), "DSN to connect to the MySQL server")
|
var dsn = flag.String("dsn", fic.DSNGenerator(), "DSN to connect to the MySQL server")
|
||||||
|
flag.StringVar(&generatorSocket, "generator", "./GENERATOR/generator.socket", "Path to the generator socket")
|
||||||
flag.StringVar(&settings.SettingsDir, "settings", "./SETTINGSDIST", "Base directory where load and save settings")
|
flag.StringVar(&settings.SettingsDir, "settings", "./SETTINGSDIST", "Base directory where load and save settings")
|
||||||
flag.StringVar(&SubmissionDir, "submission", "./submissions", "Base directory where save submissions")
|
flag.StringVar(&SubmissionDir, "submission", "./submissions", "Base directory where save submissions")
|
||||||
flag.StringVar(&TeamsDir, "teams", "./TEAMS", "Base directory where save teams JSON files")
|
flag.StringVar(&TeamsDir, "teams", "./TEAMS", "Base directory where save teams JSON files")
|
||||||
flag.StringVar(&fic.FilesDir, "files", fic.FilesDir, "Request path prefix to reach files")
|
|
||||||
var debugINotify = flag.Bool("debuginotify", false, "Show skipped inotofy events")
|
var debugINotify = flag.Bool("debuginotify", false, "Show skipped inotofy events")
|
||||||
flag.BoolVar(&skipInitialGeneration, "skipfullgeneration", skipInitialGeneration, "Skip the initial regeneration")
|
|
||||||
flag.IntVar(¶llelJobs, "jobs", parallelJobs, "Number of generation workers")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
log.SetPrefix("[backend] ")
|
log.SetPrefix("[checker] ")
|
||||||
|
|
||||||
settings.SettingsDir = path.Clean(settings.SettingsDir)
|
settings.SettingsDir = path.Clean(settings.SettingsDir)
|
||||||
SubmissionDir = path.Clean(SubmissionDir)
|
SubmissionDir = path.Clean(SubmissionDir)
|
||||||
@ -129,8 +105,6 @@ func main() {
|
|||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
launchWorkers()
|
|
||||||
|
|
||||||
log.Println("Creating submission directory...")
|
log.Println("Creating submission directory...")
|
||||||
if _, err := os.Stat(path.Join(SubmissionDir, ".tmp")); os.IsNotExist(err) {
|
if _, err := os.Stat(path.Join(SubmissionDir, ".tmp")); os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(path.Join(SubmissionDir, ".tmp"), 0777); err != nil {
|
if err := os.MkdirAll(path.Join(SubmissionDir, ".tmp"), 0777); err != nil {
|
||||||
@ -158,24 +132,23 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register SIGUSR1, SIGUSR2
|
// Register SIGUSR1 and SIGTERM
|
||||||
interrupt1 := make(chan os.Signal, 1)
|
interrupt1 := make(chan os.Signal, 1)
|
||||||
signal.Notify(interrupt1, syscall.SIGUSR1)
|
signal.Notify(interrupt1, syscall.SIGUSR1)
|
||||||
interrupt2 := make(chan os.Signal, 1)
|
interrupt := make(chan os.Signal, 1)
|
||||||
signal.Notify(interrupt2, syscall.SIGUSR2)
|
signal.Notify(interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
watchedNotify := fsnotify.Create
|
watchedNotify := fsnotify.Create
|
||||||
|
|
||||||
|
loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
case <-interrupt:
|
||||||
|
break loop
|
||||||
case <-interrupt1:
|
case <-interrupt1:
|
||||||
log.Println("SIGUSR1 received, retreating all files in queue...")
|
log.Println("SIGUSR1 received, retreating all files in queue...")
|
||||||
walkAndTreat(SubmissionDir)
|
walkAndTreat(SubmissionDir)
|
||||||
log.Println("SIGUSR1 treated.")
|
log.Println("SIGUSR1 treated.")
|
||||||
case <-interrupt2:
|
|
||||||
inQueueMutex.Lock()
|
|
||||||
log.Printf("SIGUSR2 received, dumping statistics:\n parallelJobs: %d\n genTeamQueue size: %d\n genQueue: %d\n Teams in queue: %v\n Challenge started: %v\n Last regeneration: %v\n", parallelJobs, len(genTeamQueue), len(genQueue), inGenQueue, ChStarted, lastRegeneration)
|
|
||||||
inQueueMutex.Unlock()
|
|
||||||
case ev := <-watcher.Events:
|
case ev := <-watcher.Events:
|
||||||
if d, err := os.Lstat(ev.Name); err == nil && ev.Op&fsnotify.Create == fsnotify.Create && d.Mode().IsDir() && d.Mode()&os.ModeSymlink == 0 && d.Name() != ".tmp" {
|
if d, err := os.Lstat(ev.Name); err == nil && ev.Op&fsnotify.Create == fsnotify.Create && d.Mode().IsDir() && d.Mode()&os.ModeSymlink == 0 && d.Name() != ".tmp" {
|
||||||
// Register new subdirectory
|
// Register new subdirectory
|
@ -46,8 +46,8 @@ func registrationProcess(id string, team *fic.Team, members []fic.Member, team_i
|
|||||||
log.Println(id, "[ERR]", err)
|
log.Println(id, "[ERR]", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
appendGenQueue(genStruct{Type: GenTeams})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeams})
|
||||||
}
|
}
|
||||||
|
|
||||||
func treatRegistration(pathname string, team_id string) {
|
func treatRegistration(pathname string, team_id string) {
|
||||||
@ -94,7 +94,7 @@ func treatRegistration(pathname string, team_id string) {
|
|||||||
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendGenQueue(genStruct{Type: GenEvents})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenEvents})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -38,11 +38,11 @@ func treatRename(pathname string, team *fic.Team) {
|
|||||||
if _, err := team.Update(); err != nil {
|
if _, err := team.Update(); err != nil {
|
||||||
log.Printf("%s [WRN] Unable to change team name: %s\n", id, err)
|
log.Printf("%s [WRN] Unable to change team name: %s\n", id, err)
|
||||||
}
|
}
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
if _, err := fic.NewEvent(fmt.Sprintf("Souhaitons bonne chance à l'équipe <strong>%s</strong> qui vient de nous rejoindre !", html.EscapeString(team.Name)), "info"); err != nil {
|
if _, err := fic.NewEvent(fmt.Sprintf("Souhaitons bonne chance à l'équipe <strong>%s</strong> qui vient de nous rejoindre !", html.EscapeString(team.Name)), "info"); err != nil {
|
||||||
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
||||||
}
|
}
|
||||||
appendGenQueue(genStruct{Type: GenEvents})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenEvents})
|
||||||
if err := os.Remove(pathname); err != nil {
|
if err := os.Remove(pathname); err != nil {
|
||||||
log.Printf("%s [ERR] %s\n", id, err)
|
log.Printf("%s [ERR] %s\n", id, err)
|
||||||
}
|
}
|
@ -129,7 +129,7 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
solved, err := exercice.CheckResponse(cksum[:], responses.Keys, responses.MCQs, team)
|
solved, err := exercice.CheckResponse(cksum[:], responses.Keys, responses.MCQs, team)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(id, "[ERR] Unable to CheckResponse:", err)
|
log.Println(id, "[ERR] Unable to CheckResponse:", err)
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tm != nil {
|
if tm != nil {
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
} else if solved {
|
} else if solved {
|
||||||
log.Printf("%s Team %d SOLVED exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
log.Printf("%s Team %d SOLVED exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
if err := exercice.Solved(team); err != nil {
|
if err := exercice.Solved(team); err != nil {
|
||||||
@ -152,9 +152,9 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a résolu le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "success"); err != nil {
|
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a résolu le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "success"); err != nil {
|
||||||
log.Println(id, "[WRN] Unable to create event:", err)
|
log.Println(id, "[WRN] Unable to create event:", err)
|
||||||
}
|
}
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
appendGenQueue(genStruct{id, GenThemes})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenThemes})
|
||||||
appendGenQueue(genStruct{id, GenTeams})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeams})
|
||||||
} else {
|
} else {
|
||||||
log.Printf("%s Team %d submit an invalid solution for exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
log.Printf("%s Team %d submit an invalid solution for exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
|
|
||||||
@ -166,8 +166,8 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
log.Println(id, "[WRN] Unable to create event:", err)
|
log.Println(id, "[WRN] Unable to create event:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
genTeamQueue <- team
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
}
|
}
|
||||||
|
|
||||||
appendGenQueue(genStruct{id, GenEvents})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenEvents})
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
10.10.10.1 phobos
|
10.10.10.1 phobos
|
||||||
|
|
||||||
172.17.0.2 admin
|
172.17.0.2 admin
|
||||||
172.17.0.3 backend
|
172.17.0.3 checker
|
||||||
172.17.0.4 db
|
172.17.0.4 db
|
||||||
172.17.0.5 sshd
|
172.17.0.5 generator
|
||||||
|
|
||||||
10.10.10.2 deimos
|
10.10.10.2 deimos
|
||||||
|
|
||||||
|
@ -28,11 +28,12 @@ services:
|
|||||||
- /mnt/fic:/mnt/fic:ro
|
- /mnt/fic:/mnt/fic:ro
|
||||||
- dashboard:/srv/DASHBOARD
|
- dashboard:/srv/DASHBOARD
|
||||||
- files:/srv/FILES
|
- files:/srv/FILES
|
||||||
|
- generator:/srv/GENERATOR:ro
|
||||||
- pki:/srv/PKI
|
- pki:/srv/PKI
|
||||||
- settings:/srv/SETTINGS
|
- settings:/srv/SETTINGS
|
||||||
- settingsdist:/srv/SETTINGSDIST
|
- settingsdist:/srv/SETTINGSDIST
|
||||||
- submissions:/srv/submissions
|
- submissions:/srv/submissions
|
||||||
- teams:/srv/TEAMS
|
- teams:/srv/TEAMS:ro
|
||||||
command: -baseurl /admin/ -localimport /mnt/fic -localimportsymlink
|
command: -baseurl /admin/ -localimport /mnt/fic -localimportsymlink
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql
|
- mysql
|
||||||
@ -51,20 +52,39 @@ services:
|
|||||||
- settings:/srv/SETTINGS
|
- settings:/srv/SETTINGS
|
||||||
- settingsdist:/srv/SETTINGSDIST
|
- settingsdist:/srv/SETTINGSDIST
|
||||||
|
|
||||||
backend:
|
checker:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile-backend
|
dockerfile: Dockerfile-checker
|
||||||
image: nemunaire/fic-backend:latest
|
image: nemunaire/fic-checker:latest
|
||||||
links:
|
links:
|
||||||
- mysql
|
- mysql
|
||||||
networks:
|
networks:
|
||||||
- fic-net
|
- fic-net
|
||||||
volumes:
|
volumes:
|
||||||
- files:/srv/FILES:ro
|
- generator:/srv/GENERATOR:ro
|
||||||
- teams:/srv/TEAMS
|
- teams:/srv/TEAMS:ro
|
||||||
- settingsdist:/srv/SETTINGSDIST:ro
|
- settingsdist:/srv/SETTINGSDIST:ro
|
||||||
- submissions:/srv/submissions
|
- submissions:/srv/submissions
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
- generator
|
||||||
|
environment:
|
||||||
|
- MYSQL_HOST=mysql
|
||||||
|
|
||||||
|
generator:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile-generator
|
||||||
|
image: nemunaire/fic-generator:latest
|
||||||
|
links:
|
||||||
|
- mysql
|
||||||
|
networks:
|
||||||
|
- fic-net
|
||||||
|
volumes:
|
||||||
|
- generator:/srv/GENERATOR
|
||||||
|
- teams:/srv/TEAMS
|
||||||
|
- settingsdist:/srv/SETTINGSDIST:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql
|
- mysql
|
||||||
environment:
|
environment:
|
||||||
@ -106,8 +126,6 @@ services:
|
|||||||
- settingsdist:/srv/SETTINGSDIST:ro
|
- settingsdist:/srv/SETTINGSDIST:ro
|
||||||
- submissions:/srv/submissions
|
- submissions:/srv/submissions
|
||||||
- startingblock:/srv/startingblock
|
- startingblock:/srv/startingblock
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
|
|
||||||
dashboard:
|
dashboard:
|
||||||
build:
|
build:
|
||||||
@ -123,8 +141,6 @@ services:
|
|||||||
- dashboard:/srv/DASHBOARD
|
- dashboard:/srv/DASHBOARD
|
||||||
- teams:/srv/TEAMS:ro
|
- teams:/srv/TEAMS:ro
|
||||||
- settingsdist:/srv/SETTINGSDIST:ro
|
- settingsdist:/srv/SETTINGSDIST:ro
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
|
|
||||||
front:
|
front:
|
||||||
build:
|
build:
|
||||||
@ -146,7 +162,7 @@ services:
|
|||||||
- qa
|
- qa
|
||||||
- receiver
|
- receiver
|
||||||
- dashboard
|
- dashboard
|
||||||
- backend
|
- checker
|
||||||
- admin
|
- admin
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
@ -154,6 +170,7 @@ volumes:
|
|||||||
dashboard:
|
dashboard:
|
||||||
files:
|
files:
|
||||||
htdocs:
|
htdocs:
|
||||||
|
generator:
|
||||||
pki:
|
pki:
|
||||||
settings:
|
settings:
|
||||||
settingsdist:
|
settingsdist:
|
||||||
|
@ -61,17 +61,28 @@ onboot:
|
|||||||
peer: veth-admin
|
peer: veth-admin
|
||||||
bindNS:
|
bindNS:
|
||||||
net: /run/netns/fic-admin
|
net: /run/netns/fic-admin
|
||||||
- name: backend-ip-setup
|
- name: checker-ip-setup
|
||||||
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
||||||
command: ["/bin/sh", "-c", "ip a add 172.17.0.3/24 dev vethin-backend; ip link set vethin-backend up;" ]
|
command: ["/bin/sh", "-c", "ip a add 172.17.0.3/24 dev vethin-checker; ip link set vethin-checker up;" ]
|
||||||
net: new
|
net: new
|
||||||
runtime:
|
runtime:
|
||||||
interfaces:
|
interfaces:
|
||||||
- name: vethin-backend
|
- name: vethin-checker
|
||||||
add: veth
|
add: veth
|
||||||
peer: veth-backend
|
peer: veth-checker
|
||||||
bindNS:
|
bindNS:
|
||||||
net: /run/netns/fic-backend
|
net: /run/netns/fic-checker
|
||||||
|
- name: generator-ip-setup
|
||||||
|
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
||||||
|
command: ["/bin/sh", "-c", "ip a add 172.17.0.5/24 dev vethin-generator; ip link set vethin-generator up;" ]
|
||||||
|
net: new
|
||||||
|
runtime:
|
||||||
|
interfaces:
|
||||||
|
- name: vethin-generator
|
||||||
|
add: veth
|
||||||
|
peer: veth-generator
|
||||||
|
bindNS:
|
||||||
|
net: /run/netns/fic-generator
|
||||||
- name: mysql-ip-setup
|
- name: mysql-ip-setup
|
||||||
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
||||||
command: ["/bin/sh", "-c", "ip a add 172.17.0.4/24 dev vethin-db; ip link set vethin-db up;" ]
|
command: ["/bin/sh", "-c", "ip a add 172.17.0.4/24 dev vethin-db; ip link set vethin-db up;" ]
|
||||||
@ -85,7 +96,7 @@ onboot:
|
|||||||
net: /run/netns/db
|
net: /run/netns/db
|
||||||
- name: bridge-setup
|
- name: bridge-setup
|
||||||
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
image: linuxkit/ip:c88e3272e3b12edec454e4720da8bb70a7655bc7
|
||||||
command: ["/bin/sh", "-c", "ip a add 172.17.0.1/24 dev br0; ip link set veth-admin master br0; ip link set veth-backend master br0; ip link set veth-db master br0; ip link set br0 up; ip link set veth-admin up; ip link set veth-backend up; ip link set veth-db up;" ]
|
command: ["/bin/sh", "-c", "ip a add 172.17.0.1/24 dev br0; ip link set veth-admin master br0; ip link set veth-checker master br0; ip link set veth-generator master br0; ip link set veth-db master br0; ip link set br0 up; ip link set veth-admin up; ip link set veth-checker up; ip link set veth-generator up; ip link set veth-db up;" ]
|
||||||
runtime:
|
runtime:
|
||||||
interfaces:
|
interfaces:
|
||||||
- name: br0
|
- name: br0
|
||||||
@ -173,11 +184,11 @@ services:
|
|||||||
- /var/lib/fic/raw_files:/mnt/fic
|
- /var/lib/fic/raw_files:/mnt/fic
|
||||||
- /var/lib/fic/dashboard:/srv/DASHBOARD
|
- /var/lib/fic/dashboard:/srv/DASHBOARD
|
||||||
- /var/lib/fic/files:/srv/FILES
|
- /var/lib/fic/files:/srv/FILES
|
||||||
|
- /var/lib/fic/generator:/srv/GENERATOR:ro
|
||||||
- /var/lib/fic/pki:/srv/PKI
|
- /var/lib/fic/pki:/srv/PKI
|
||||||
- /var/lib/fic/teams:/srv/TEAMS
|
|
||||||
- /var/lib/fic/settings:/srv/SETTINGS
|
- /var/lib/fic/settings:/srv/SETTINGS
|
||||||
- /var/lib/fic/sync:/srv/SYNC
|
|
||||||
- /var/lib/fic/submissions:/srv/submissions:ro
|
- /var/lib/fic/submissions:/srv/submissions:ro
|
||||||
|
- /var/lib/fic/teams:/srv/TEAMS:ro
|
||||||
net: /run/netns/fic-admin
|
net: /run/netns/fic-admin
|
||||||
pid: new
|
pid: new
|
||||||
ipc: new
|
ipc: new
|
||||||
@ -186,10 +197,10 @@ services:
|
|||||||
mkdir:
|
mkdir:
|
||||||
- /var/lib/fic/dashboard
|
- /var/lib/fic/dashboard
|
||||||
- /var/lib/fic/files
|
- /var/lib/fic/files
|
||||||
|
- /var/lib/fic/generator
|
||||||
- /var/lib/fic/raw_files
|
- /var/lib/fic/raw_files
|
||||||
- /var/lib/fic/pki
|
- /var/lib/fic/pki
|
||||||
- /var/lib/fic/settings
|
- /var/lib/fic/settings
|
||||||
- /var/lib/fic/sync
|
|
||||||
- /var/lib/fic/submissions
|
- /var/lib/fic/submissions
|
||||||
- /var/lib/fic/teams
|
- /var/lib/fic/teams
|
||||||
- name: fic-evdist
|
- name: fic-evdist
|
||||||
@ -206,21 +217,24 @@ services:
|
|||||||
mkdir:
|
mkdir:
|
||||||
- /var/lib/fic/settings
|
- /var/lib/fic/settings
|
||||||
- /var/lib/fic/settingsdist
|
- /var/lib/fic/settingsdist
|
||||||
- name: fic-backend
|
- name: fic-checker
|
||||||
image: nemunaire/fic-backend:latest@sha256:12d3286cdbe6d18d284f21432b4eb92ce8ab9844982177562069bc0f9536c93b
|
image: nemunaire/fic-checker:latest@sha256:12d3286cdbe6d18d284f21432b4eb92ce8ab9844982177562069bc0f9536c93b
|
||||||
env:
|
env:
|
||||||
- MYSQL_HOST=db
|
- MYSQL_HOST=db
|
||||||
|
- MYSQL_PASSWORD=fic
|
||||||
binds:
|
binds:
|
||||||
- /etc/hosts:/etc/hosts:ro
|
- /etc/hosts:/etc/hosts:ro
|
||||||
- /var/lib/fic/teams:/srv/TEAMS
|
- /var/lib/fic/generator:/srv/GENERATOR:ro
|
||||||
|
- /var/lib/fic/teams:/srv/TEAMS:ro
|
||||||
- /var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro
|
- /var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro
|
||||||
- /var/lib/fic/submissions:/srv/submissions
|
- /var/lib/fic/submissions:/srv/submissions
|
||||||
net: /run/netns/fic-backend
|
net: /run/netns/fic-checker
|
||||||
pid: new
|
pid: new
|
||||||
ipc: new
|
ipc: new
|
||||||
uts: new
|
uts: new
|
||||||
runtime:
|
runtime:
|
||||||
mkdir:
|
mkdir:
|
||||||
|
- /var/lib/fic/generator
|
||||||
- /var/lib/fic/settingsdist
|
- /var/lib/fic/settingsdist
|
||||||
- /var/lib/fic/submissions
|
- /var/lib/fic/submissions
|
||||||
- /var/lib/fic/teams
|
- /var/lib/fic/teams
|
||||||
@ -242,6 +256,26 @@ services:
|
|||||||
- /var/lib/fic/dashboard
|
- /var/lib/fic/dashboard
|
||||||
- /var/lib/fic/teams
|
- /var/lib/fic/teams
|
||||||
- /var/lib/fic/settingsdist
|
- /var/lib/fic/settingsdist
|
||||||
|
- name: fic-generator
|
||||||
|
image: nemunaire/fic-generator:latest@sha256:12d3286cdbe6d18d284f21432b4eb92ce8ab9844982177562069bc0f9536c93b
|
||||||
|
command: ["/srv/generator", "-bind=/srv/GENERATOR/generator.socket"]
|
||||||
|
env:
|
||||||
|
- MYSQL_HOST=db
|
||||||
|
- MYSQL_PASSWORD=fic
|
||||||
|
binds:
|
||||||
|
- /etc/hosts:/etc/hosts:ro
|
||||||
|
- /var/lib/fic/generator:/srv/GENERATOR:ro
|
||||||
|
- /var/lib/fic/teams:/srv/TEAMS
|
||||||
|
- /var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro
|
||||||
|
net: /run/netns/fic-generator
|
||||||
|
pid: new
|
||||||
|
ipc: new
|
||||||
|
uts: new
|
||||||
|
runtime:
|
||||||
|
mkdir:
|
||||||
|
- /var/lib/fic/generator
|
||||||
|
- /var/lib/fic/settingsdist
|
||||||
|
- /var/lib/fic/teams
|
||||||
- name: fic-synchro
|
- name: fic-synchro
|
||||||
image: nemunaire/rsync:a3d76b2dd0a9ad73be44dc77ad765b20d96a3285
|
image: nemunaire/rsync:a3d76b2dd0a9ad73be44dc77ad765b20d96a3285
|
||||||
command: ["/bin/ash", "/root/synchro.sh"]
|
command: ["/bin/ash", "/root/synchro.sh"]
|
||||||
|
14
flake.nix
14
flake.nix
@ -40,12 +40,12 @@
|
|||||||
subPackages = [ "admin" ];
|
subPackages = [ "admin" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
fic-backend = pkgs.buildGoModule {
|
fic-checker = pkgs.buildGoModule {
|
||||||
pname = "backend";
|
pname = "checker";
|
||||||
inherit version vendorSha256 overrideModAttrs;
|
inherit version vendorSha256 overrideModAttrs;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
subPackages = [ "backend" ];
|
subPackages = [ "checker" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
fic-dashboard = pkgs.buildGoModule {
|
fic-dashboard = pkgs.buildGoModule {
|
||||||
@ -56,6 +56,14 @@
|
|||||||
subPackages = [ "dashboard" ];
|
subPackages = [ "dashboard" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fic-generator = pkgs.buildGoModule {
|
||||||
|
pname = "generator";
|
||||||
|
inherit version vendorSha256 overrideModAttrs;
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
subPackages = [ "generator" ];
|
||||||
|
};
|
||||||
|
|
||||||
fic-synchro = pkgs.writeShellApplication {
|
fic-synchro = pkgs.writeShellApplication {
|
||||||
name = "synchro";
|
name = "synchro";
|
||||||
runtimeInputs = [ pkgs.rsync pkgs.openssh pkgs.coreutils ];
|
runtimeInputs = [ pkgs.rsync pkgs.openssh pkgs.coreutils ];
|
||||||
|
1
generator/.gitignore
vendored
Normal file
1
generator/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
generator
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -13,30 +14,14 @@ import (
|
|||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenerateType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
GenPublic GenerateType = iota
|
|
||||||
GenEvents
|
|
||||||
GenTeams
|
|
||||||
GenThemes
|
|
||||||
)
|
|
||||||
|
|
||||||
type genStruct struct {
|
|
||||||
Id string
|
|
||||||
Type GenerateType
|
|
||||||
}
|
|
||||||
|
|
||||||
var parallelJobs = runtime.NumCPU()
|
var parallelJobs = runtime.NumCPU()
|
||||||
var genTeamQueue chan *fic.Team
|
var genQueue chan fic.GenStruct
|
||||||
var genQueue chan genStruct
|
|
||||||
var inQueueMutex sync.RWMutex
|
var inQueueMutex sync.RWMutex
|
||||||
var inGenQueue map[GenerateType]bool
|
var inGenQueue map[fic.GenerateType]bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
genTeamQueue = make(chan *fic.Team)
|
genQueue = make(chan fic.GenStruct)
|
||||||
genQueue = make(chan genStruct)
|
inGenQueue = map[fic.GenerateType]bool{}
|
||||||
inGenQueue = map[GenerateType]bool{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func launchWorkers() {
|
func launchWorkers() {
|
||||||
@ -46,7 +31,29 @@ func launchWorkers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendGenQueue(gs genStruct) {
|
func enqueueHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var gs fic.GenStruct
|
||||||
|
|
||||||
|
dec := json.NewDecoder(r.Body)
|
||||||
|
err := dec.Decode(&gs)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("POST /enqueue | %v", gs)
|
||||||
|
|
||||||
|
appendGenQueue(gs)
|
||||||
|
http.Error(w, "OK", http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendGenQueue(gs fic.GenStruct) {
|
||||||
|
if gs.Type == fic.GenTeam || gs.Type == fic.GenTeamIssues {
|
||||||
|
genQueue <- gs
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append only if not already in queue
|
||||||
inQueueMutex.RLock()
|
inQueueMutex.RLock()
|
||||||
if v, ok := inGenQueue[gs.Type]; !ok || !v {
|
if v, ok := inGenQueue[gs.Type]; !ok || !v {
|
||||||
inQueueMutex.RUnlock()
|
inQueueMutex.RUnlock()
|
||||||
@ -62,31 +69,30 @@ func appendGenQueue(gs genStruct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func consumer() {
|
func consumer() {
|
||||||
|
var id string
|
||||||
|
var err error
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var id string
|
gs := <-genQueue
|
||||||
var err error
|
id = gs.Id
|
||||||
|
|
||||||
select {
|
inQueueMutex.Lock()
|
||||||
case gt := <-genTeamQueue:
|
inGenQueue[gs.Type] = false
|
||||||
err = genTeamMyFile(gt)
|
inQueueMutex.Unlock()
|
||||||
|
|
||||||
case gs := <-genQueue:
|
switch gs.Type {
|
||||||
id = gs.Id
|
case fic.GenPublic:
|
||||||
|
err = genMyPublicFile()
|
||||||
inQueueMutex.Lock()
|
case fic.GenEvents:
|
||||||
inGenQueue[gs.Type] = false
|
err = genEventsFile()
|
||||||
inQueueMutex.Unlock()
|
case fic.GenTeam:
|
||||||
|
err = genTeamMyFile(gs.TeamId)
|
||||||
switch gs.Type {
|
case fic.GenTeams:
|
||||||
case GenPublic:
|
err = genTeamsFile()
|
||||||
err = genMyPublicFile()
|
case fic.GenThemes:
|
||||||
case GenEvents:
|
err = genThemesFile()
|
||||||
err = genEventsFile()
|
case fic.GenTeamIssues:
|
||||||
case GenTeams:
|
err = genTeamIssuesFile(gs.TeamId)
|
||||||
err = genTeamsFile()
|
|
||||||
case GenThemes:
|
|
||||||
err = genThemesFile()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -96,18 +102,36 @@ func consumer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate issues.json for a given team
|
// Generate issues.json for a given team
|
||||||
func genTeamIssuesFile(team *fic.Team) error {
|
func genTeamIssuesFile(teamid int64) error {
|
||||||
|
team, err := fic.GetTeam(teamid)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to GetTeam: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
||||||
|
|
||||||
|
my, err := team.MyIssueFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if my == nil {
|
||||||
|
if _, err := os.Stat(path.Join(dirPath, "issues.json")); !os.IsNotExist(err) {
|
||||||
|
err = os.Remove(path.Join(dirPath, "issues.json"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to remove empty issues file: %s", path.Join(dirPath, "issues.json"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if s, err := os.Stat(dirPath); os.IsNotExist(err) {
|
if s, err := os.Stat(dirPath); os.IsNotExist(err) {
|
||||||
os.MkdirAll(dirPath, 0777)
|
os.MkdirAll(dirPath, 0777)
|
||||||
} else if !s.IsDir() {
|
} else if !s.IsDir() {
|
||||||
return fmt.Errorf("%s is not a directory", dirPath)
|
return fmt.Errorf("%s is not a directory", dirPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if my, err := team.MyIssueFile(); err != nil {
|
if j, err := json.Marshal(my); err != nil {
|
||||||
return err
|
|
||||||
} else if j, err := json.Marshal(my); err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else if err = ioutil.WriteFile(path.Join(dirPath, "issues.json"), j, 0644); err != nil {
|
} else if err = ioutil.WriteFile(path.Join(dirPath, "issues.json"), j, 0644); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -117,7 +141,12 @@ func genTeamIssuesFile(team *fic.Team) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate my.json, wait.json and scores.json for a given team
|
// Generate my.json, wait.json and scores.json for a given team
|
||||||
func genTeamMyFile(team *fic.Team) error {
|
func genTeamMyFile(teamid int64) error {
|
||||||
|
team, err := fic.GetTeam(teamid)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to GetTeam: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
||||||
|
|
||||||
if s, err := os.Stat(dirPath); os.IsNotExist(err) {
|
if s, err := os.Stat(dirPath); os.IsNotExist(err) {
|
||||||
@ -235,17 +264,17 @@ func genThemesFile() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func genAll() {
|
func genAll() {
|
||||||
appendGenQueue(genStruct{Type: GenThemes})
|
appendGenQueue(fic.GenStruct{Type: fic.GenThemes})
|
||||||
appendGenQueue(genStruct{Type: GenTeams})
|
appendGenQueue(fic.GenStruct{Type: fic.GenTeams})
|
||||||
appendGenQueue(genStruct{Type: GenEvents})
|
appendGenQueue(fic.GenStruct{Type: fic.GenEvents})
|
||||||
appendGenQueue(genStruct{Type: GenPublic})
|
appendGenQueue(fic.GenStruct{Type: fic.GenPublic})
|
||||||
|
|
||||||
if teams, err := fic.GetActiveTeams(); err != nil {
|
if teams, err := fic.GetActiveTeams(); err != nil {
|
||||||
log.Println("Team retrieval error: ", err)
|
log.Println("Team retrieval error: ", err)
|
||||||
} else {
|
} else {
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
myteam := team // team is reused, we need to create a new variable here to store the value
|
appendGenQueue(fic.GenStruct{Type: fic.GenTeam, TeamId: team.Id})
|
||||||
genTeamQueue <- myteam
|
appendGenQueue(fic.GenStruct{Type: fic.GenTeamIssues, TeamId: team.Id})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
151
generator/main.go
Normal file
151
generator/main.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
"srs.epita.fr/fic-server/settings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TeamsDir string
|
||||||
|
|
||||||
|
var ChStarted = false
|
||||||
|
var lastRegeneration time.Time
|
||||||
|
var skipInitialGeneration = false
|
||||||
|
|
||||||
|
func reloadSettings(config *settings.Settings) {
|
||||||
|
fic.HintCoefficient = config.HintCurCoefficient
|
||||||
|
fic.WChoiceCoefficient = config.WChoiceCurCoefficient
|
||||||
|
fic.ExerciceCurrentCoefficient = config.ExerciceCurCoefficient
|
||||||
|
ChStarted = config.Start.Unix() > 0 && time.Since(config.Start) >= 0
|
||||||
|
if lastRegeneration != config.Generation || fic.PartialValidation != config.PartialValidation || fic.UnlockedChallengeDepth != config.UnlockedChallengeDepth || fic.UnlockedChallengeUpTo != config.UnlockedChallengeUpTo || fic.DisplayAllFlags != config.DisplayAllFlags || fic.FirstBlood != config.FirstBlood || fic.SubmissionCostBase != config.SubmissionCostBase || fic.SubmissionUniqueness != config.SubmissionUniqueness || fic.DiscountedFactor != config.DiscountedFactor {
|
||||||
|
fic.PartialValidation = config.PartialValidation
|
||||||
|
fic.UnlockedChallengeDepth = config.UnlockedChallengeDepth
|
||||||
|
fic.UnlockedChallengeUpTo = config.UnlockedChallengeUpTo
|
||||||
|
fic.DisplayAllFlags = config.DisplayAllFlags
|
||||||
|
|
||||||
|
fic.FirstBlood = config.FirstBlood
|
||||||
|
fic.SubmissionCostBase = config.SubmissionCostBase
|
||||||
|
fic.SubmissionUniqueness = config.SubmissionUniqueness
|
||||||
|
fic.GlobalScoreCoefficient = config.GlobalScoreCoefficient
|
||||||
|
fic.CountOnlyNotGoodTries = config.CountOnlyNotGoodTries
|
||||||
|
fic.DiscountedFactor = config.DiscountedFactor
|
||||||
|
|
||||||
|
if !skipInitialGeneration {
|
||||||
|
log.Println("Generating files...")
|
||||||
|
go func() {
|
||||||
|
genAll()
|
||||||
|
log.Println("Full generation done")
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
skipInitialGeneration = false
|
||||||
|
log.Println("Regeneration skipped by option.")
|
||||||
|
}
|
||||||
|
lastRegeneration = config.Generation
|
||||||
|
} else {
|
||||||
|
log.Println("No change found. Skipping regeneration.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if v, exists := os.LookupEnv("FIC_BASEURL"); exists {
|
||||||
|
fic.FilesDir = v + "files"
|
||||||
|
} else {
|
||||||
|
fic.FilesDir = "/files"
|
||||||
|
}
|
||||||
|
|
||||||
|
var bind = flag.String("bind", "./GENERATOR/generator.socket", "Bind path or port/socket")
|
||||||
|
var dsn = flag.String("dsn", fic.DSNGenerator(), "DSN to connect to the MySQL server")
|
||||||
|
flag.StringVar(&settings.SettingsDir, "settings", "./SETTINGSDIST", "Base directory where load and save settings")
|
||||||
|
flag.StringVar(&TeamsDir, "teams", "./TEAMS", "Base directory where save teams JSON files")
|
||||||
|
flag.StringVar(&fic.FilesDir, "files", fic.FilesDir, "Request path prefix to reach files")
|
||||||
|
flag.BoolVar(&skipInitialGeneration, "skipfullgeneration", skipInitialGeneration, "Skip the initial regeneration")
|
||||||
|
flag.IntVar(¶llelJobs, "jobs", parallelJobs, "Number of generation workers")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
log.SetPrefix("[generator] ")
|
||||||
|
|
||||||
|
settings.SettingsDir = path.Clean(settings.SettingsDir)
|
||||||
|
TeamsDir = path.Clean(TeamsDir)
|
||||||
|
|
||||||
|
launchWorkers()
|
||||||
|
|
||||||
|
log.Println("Opening DB...")
|
||||||
|
if err := fic.DBInit(*dsn); err != nil {
|
||||||
|
log.Fatal("Cannot open the database: ", err)
|
||||||
|
}
|
||||||
|
defer fic.DBClose()
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
settings.LoadAndWatchSettings(path.Join(settings.SettingsDir, settings.SettingsFile), reloadSettings)
|
||||||
|
|
||||||
|
// Register SIGUSR1, SIGUSR2
|
||||||
|
interrupt1 := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt1, syscall.SIGUSR1)
|
||||||
|
interrupt2 := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt2, syscall.SIGUSR2)
|
||||||
|
|
||||||
|
// Prepare graceful shutdown
|
||||||
|
interrupt := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: *bind,
|
||||||
|
}
|
||||||
|
|
||||||
|
http.HandleFunc("/enqueue", enqueueHandler)
|
||||||
|
|
||||||
|
// Serve pages
|
||||||
|
go func() {
|
||||||
|
if !strings.Contains(*bind, ":") {
|
||||||
|
if _, err := os.Stat(*bind); !os.IsNotExist(err) {
|
||||||
|
if err := os.Remove(*bind); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.MkdirAll(path.Dir(*bind), 0777)
|
||||||
|
|
||||||
|
unixListener, err := net.Listen("unix", *bind)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Fatal(srv.Serve(unixListener))
|
||||||
|
} else if err := srv.ListenAndServe(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
log.Println(fmt.Sprintf("Ready, listening on %s", *bind))
|
||||||
|
|
||||||
|
// Wait shutdown signal
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-interrupt:
|
||||||
|
break loop
|
||||||
|
case <-interrupt1:
|
||||||
|
log.Println("SIGUSR1 received, regenerating all files...")
|
||||||
|
genAll()
|
||||||
|
log.Println("SIGUSR1 treated.")
|
||||||
|
case <-interrupt2:
|
||||||
|
inQueueMutex.Lock()
|
||||||
|
log.Printf("SIGUSR2 received, dumping statistics:\n parallelJobs: %d\n genQueue: %d\n Teams in queue: %v\n Challenge started: %v\n Last regeneration: %v\n", parallelJobs, len(genQueue), inGenQueue, ChStarted, lastRegeneration)
|
||||||
|
inQueueMutex.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Print("The service is shutting down...")
|
||||||
|
srv.Shutdown(context.Background())
|
||||||
|
log.Println("done")
|
||||||
|
}
|
18
libfic/generation.go
Normal file
18
libfic/generation.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package fic
|
||||||
|
|
||||||
|
type GenerateType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
GenPublic GenerateType = iota
|
||||||
|
GenEvents
|
||||||
|
GenTeam
|
||||||
|
GenTeams
|
||||||
|
GenThemes
|
||||||
|
GenTeamIssues
|
||||||
|
)
|
||||||
|
|
||||||
|
type GenStruct struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Type GenerateType `json:"type"`
|
||||||
|
TeamId int64 `json:"team_id,omitempty"`
|
||||||
|
}
|
@ -3,9 +3,10 @@
|
|||||||
imports = [
|
imports = [
|
||||||
./db.nix
|
./db.nix
|
||||||
./fic-admin.nix
|
./fic-admin.nix
|
||||||
./fic-backend.nix
|
./fic-checker.nix
|
||||||
./fic-dashboard.nix
|
./fic-dashboard.nix
|
||||||
./fic-evdist.nix
|
./fic-evdist.nix
|
||||||
|
./fic-generator.nix
|
||||||
./fic-synchro.nix
|
./fic-synchro.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
};
|
};
|
||||||
volumes = [
|
volumes = [
|
||||||
"/etc/hosts:/etc/hosts:ro"
|
"/etc/hosts:/etc/hosts:ro"
|
||||||
|
"/var/lib/fic/generator:/srv/GENERATOR:ro"
|
||||||
"/var/lib/fic/raw_files:/mnt/fic"
|
"/var/lib/fic/raw_files:/mnt/fic"
|
||||||
"/var/lib/fic/dashboard:/srv/DASHBOARD"
|
"/var/lib/fic/dashboard:/srv/DASHBOARD"
|
||||||
"/var/lib/fic/files:/srv/FILES"
|
"/var/lib/fic/files:/srv/FILES"
|
||||||
"/var/lib/fic/pki:/srv/PKI"
|
"/var/lib/fic/pki:/srv/PKI"
|
||||||
"/var/lib/fic/teams:/srv/TEAMS"
|
"/var/lib/fic/teams:/srv/TEAMS:ro"
|
||||||
"/var/lib/fic/settings:/srv/SETTINGS"
|
"/var/lib/fic/settings:/srv/SETTINGS"
|
||||||
"/var/lib/fic/sync:/srv/SYNC"
|
|
||||||
"/var/lib/fic/submissions:/srv/submissions:ro"
|
"/var/lib/fic/submissions:/srv/submissions:ro"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
27
nixos/backend/fic-checker.nix
Normal file
27
nixos/backend/fic-checker.nix
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{ config, inputs, pkgs, ... }:
|
||||||
|
{
|
||||||
|
config.virtualisation.oci-containers.containers.fic-checker = {
|
||||||
|
image = "fic-checker:latest";
|
||||||
|
imageFile = pkgs.dockerTools.buildImage {
|
||||||
|
name = "fic-checker";
|
||||||
|
tag = "latest";
|
||||||
|
created = "now";
|
||||||
|
config = {
|
||||||
|
Cmd = [ "${inputs.ficpkgs.packages.x86_64-linux.fic-checker}/bin/checker" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
autoStart = true;
|
||||||
|
environment = {
|
||||||
|
MYSQL_HOST = "db";
|
||||||
|
};
|
||||||
|
workdir = "/srv";
|
||||||
|
extraOptions = [ "--network=phobos-lan" "--ip=172.18.0.41" ];
|
||||||
|
volumes = [
|
||||||
|
"/etc/hosts:/etc/hosts:ro"
|
||||||
|
"/var/lib/fic/generator:/srv/GENERATOR:ro"
|
||||||
|
"/var/lib/fic/teams:/srv/TEAMS:ro"
|
||||||
|
"/var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro"
|
||||||
|
"/var/lib/fic/submissions:/srv/submissions"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
@ -1,13 +1,13 @@
|
|||||||
{ config, inputs, pkgs, ... }:
|
{ config, inputs, pkgs, ... }:
|
||||||
{
|
{
|
||||||
config.virtualisation.oci-containers.containers.fic-backend = {
|
config.virtualisation.oci-containers.containers.fic-generator = {
|
||||||
image = "fic-backend:latest";
|
image = "fic-generator:latest";
|
||||||
imageFile = pkgs.dockerTools.buildImage {
|
imageFile = pkgs.dockerTools.buildImage {
|
||||||
name = "fic-backend";
|
name = "fic-generator";
|
||||||
tag = "latest";
|
tag = "latest";
|
||||||
created = "now";
|
created = "now";
|
||||||
config = {
|
config = {
|
||||||
Cmd = [ "${inputs.ficpkgs.packages.x86_64-linux.fic-backend}/bin/backend" ];
|
Cmd = [ "${inputs.ficpkgs.packages.x86_64-linux.fic-generator}/bin/generator" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
@ -18,9 +18,9 @@
|
|||||||
extraOptions = [ "--network=phobos-lan" "--ip=172.18.0.41" ];
|
extraOptions = [ "--network=phobos-lan" "--ip=172.18.0.41" ];
|
||||||
volumes = [
|
volumes = [
|
||||||
"/etc/hosts:/etc/hosts:ro"
|
"/etc/hosts:/etc/hosts:ro"
|
||||||
|
"/var/lib/fic/generator:/srv/GENERATOR"
|
||||||
"/var/lib/fic/teams:/srv/TEAMS"
|
"/var/lib/fic/teams:/srv/TEAMS"
|
||||||
"/var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro"
|
"/var/lib/fic/settingsdist:/srv/SETTINGSDIST:ro"
|
||||||
"/var/lib/fic/submissions:/srv/submissions"
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user