Skip to content

Commit 9489ebc

Browse files
Merge pull request #320 from ClusterCockpit/hotfix
Fixes for Bugfix Release 1.4.2
2 parents 16bcaef + 2a5c525 commit 9489ebc

21 files changed

+1119
-1206
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ TARGET = ./cc-backend
22
VAR = ./var
33
CFG = config.json .env
44
FRONTEND = ./web/frontend
5-
VERSION = 1.4.1
5+
VERSION = 1.4.2
66
GIT_HASH := $(shell git rev-parse --short HEAD || echo 'development')
77
CURRENT_TIME = $(shell date +"%Y-%m-%d:T%H:%M:%S")
88
LD_FLAGS = '-s -X main.date=${CURRENT_TIME} -X main.version=${VERSION} -X main.commit=${GIT_HASH}'

ReleaseNotes.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# `cc-backend` version 1.4.1
1+
# `cc-backend` version 1.4.2
22

33
Supports job archive version 2 and database version 8.
44

@@ -12,7 +12,8 @@ For release specific notes visit the [ClusterCockpit Documentation](https://clus
1212
migration might require several hours!
1313
- You need to adapt the `cluster.json` configuration files in the job-archive,
1414
add new required attributes to the metric list and after that edit
15-
`./job-archive/version.txt` to version 2.
15+
`./job-archive/version.txt` to version 2. Only metrics that have the footprint
16+
attribute set can be filtered and show up in the footprint UI and polar plot.
1617
- Continuous scrolling is default now in all job lists. You can change this back
1718
to paging globally, also every user can configure to use paging or continuous
1819
scrolling individually.

cmd/cc-backend/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func main() {
112112

113113
if flagInit {
114114
initEnv()
115-
fmt.Print("Succesfully setup environment!\n")
115+
fmt.Print("Successfully setup environment!\n")
116116
fmt.Print("Please review config.json and .env and adjust it to your needs.\n")
117117
fmt.Print("Add your job-archive at ./var/job-archive.\n")
118118
os.Exit(0)

cmd/cc-backend/server.go

-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/ClusterCockpit/cc-backend/internal/config"
2626
"github.com/ClusterCockpit/cc-backend/internal/graph"
2727
"github.com/ClusterCockpit/cc-backend/internal/graph/generated"
28-
"github.com/ClusterCockpit/cc-backend/internal/repository"
2928
"github.com/ClusterCockpit/cc-backend/internal/routerConfig"
3029
"github.com/ClusterCockpit/cc-backend/pkg/log"
3130
"github.com/ClusterCockpit/cc-backend/pkg/runtimeEnv"
@@ -314,9 +313,6 @@ func serverShutdown() {
314313
// First shut down the server gracefully (waiting for all ongoing requests)
315314
server.Shutdown(context.Background())
316315

317-
// Then, wait for any async jobStarts still pending...
318-
repository.WaitForJobStart()
319-
320316
// Then, wait for any async archivings still pending...
321317
archiver.WaitForArchiving()
322318
}

init/clustercockpit.service

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[Unit]
2-
Description=ClusterCockpit Web Server (Go edition)
2+
Description=ClusterCockpit Web Server
33
Documentation=https://github.com/ClusterCockpit/cc-backend
44
Wants=network-online.target
55
After=network-online.target

internal/api/api_test.go

-3
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,6 @@ func TestRestApi(t *testing.T) {
249249
if response.StatusCode != http.StatusCreated {
250250
t.Fatal(response.Status, recorder.Body.String())
251251
}
252-
253-
time.Sleep(1 * time.Second)
254-
255252
resolver := graph.GetResolverInstance()
256253
job, err := restapi.JobRepository.Find(&TestJobId, &TestClusterName, &TestStartTime)
257254
if err != nil {

internal/api/rest.go

+29-19
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,8 @@ func (api *RestApi) MountFrontendApiRoutes(r *mux.Router) {
123123
}
124124
}
125125

126-
// StartJobApiResponse model
127-
type StartJobApiResponse struct {
128-
Message string `json:"msg"`
129-
}
130-
131-
// DeleteJobApiResponse model
132-
type DeleteJobApiResponse struct {
133-
Message string `json:"msg"`
134-
}
135-
136-
// UpdateUserApiResponse model
137-
type UpdateUserApiResponse struct {
126+
// DefaultApiResponse model
127+
type DefaultJobApiResponse struct {
138128
Message string `json:"msg"`
139129
}
140130

@@ -341,7 +331,7 @@ func (api *RestApi) getJobs(rw http.ResponseWriter, r *http.Request) {
341331
withMetadata := false
342332
filter := &model.JobFilter{}
343333
page := &model.PageRequest{ItemsPerPage: 25, Page: 1}
344-
order := &model.OrderByInput{Field: "startTime", Order: model.SortDirectionEnumDesc}
334+
order := &model.OrderByInput{Field: "startTime", Type: "col", Order: model.SortDirectionEnumDesc}
345335

346336
for key, vals := range r.URL.Query() {
347337
switch key {
@@ -790,6 +780,11 @@ func (api *RestApi) startJob(rw http.ResponseWriter, r *http.Request) {
790780
return
791781
}
792782

783+
// aquire lock to avoid race condition between API calls
784+
var unlockOnce sync.Once
785+
api.RepositoryMutex.Lock()
786+
defer unlockOnce.Do(api.RepositoryMutex.Unlock)
787+
793788
// Check if combination of (job_id, cluster_id, start_time) already exists:
794789
jobs, err := api.JobRepository.FindAll(&req.JobID, &req.Cluster, nil)
795790
if err != nil && err != sql.ErrNoRows {
@@ -804,12 +799,27 @@ func (api *RestApi) startJob(rw http.ResponseWriter, r *http.Request) {
804799
}
805800
}
806801

807-
repository.TriggerJobStart(repository.JobWithUser{Job: &req, User: repository.GetUserFromContext(r.Context())})
802+
id, err := api.JobRepository.Start(&req)
803+
if err != nil {
804+
handleError(fmt.Errorf("insert into database failed: %w", err), http.StatusInternalServerError, rw)
805+
return
806+
}
807+
// unlock here, adding Tags can be async
808+
unlockOnce.Do(api.RepositoryMutex.Unlock)
809+
810+
for _, tag := range req.Tags {
811+
if _, err := api.JobRepository.AddTagOrCreate(repository.GetUserFromContext(r.Context()), id, tag.Type, tag.Name, tag.Scope); err != nil {
812+
http.Error(rw, err.Error(), http.StatusInternalServerError)
813+
handleError(fmt.Errorf("adding tag to new job %d failed: %w", id, err), http.StatusInternalServerError, rw)
814+
return
815+
}
816+
}
808817

818+
log.Printf("new job (id: %d): cluster=%s, jobId=%d, user=%s, startTime=%d", id, req.Cluster, req.JobID, req.User, req.StartTime)
809819
rw.Header().Add("Content-Type", "application/json")
810820
rw.WriteHeader(http.StatusCreated)
811-
json.NewEncoder(rw).Encode(StartJobApiResponse{
812-
Message: fmt.Sprintf("Successfully triggered job start"),
821+
json.NewEncoder(rw).Encode(DefaultJobApiResponse{
822+
Message: "success",
813823
})
814824
}
815825

@@ -892,7 +902,7 @@ func (api *RestApi) deleteJobById(rw http.ResponseWriter, r *http.Request) {
892902
}
893903
rw.Header().Add("Content-Type", "application/json")
894904
rw.WriteHeader(http.StatusOK)
895-
json.NewEncoder(rw).Encode(DeleteJobApiResponse{
905+
json.NewEncoder(rw).Encode(DefaultJobApiResponse{
896906
Message: fmt.Sprintf("Successfully deleted job %s", id),
897907
})
898908
}
@@ -943,7 +953,7 @@ func (api *RestApi) deleteJobByRequest(rw http.ResponseWriter, r *http.Request)
943953

944954
rw.Header().Add("Content-Type", "application/json")
945955
rw.WriteHeader(http.StatusOK)
946-
json.NewEncoder(rw).Encode(DeleteJobApiResponse{
956+
json.NewEncoder(rw).Encode(DefaultJobApiResponse{
947957
Message: fmt.Sprintf("Successfully deleted job %d", job.ID),
948958
})
949959
}
@@ -987,7 +997,7 @@ func (api *RestApi) deleteJobBefore(rw http.ResponseWriter, r *http.Request) {
987997

988998
rw.Header().Add("Content-Type", "application/json")
989999
rw.WriteHeader(http.StatusOK)
990-
json.NewEncoder(rw).Encode(DeleteJobApiResponse{
1000+
json.NewEncoder(rw).Encode(DefaultJobApiResponse{
9911001
Message: fmt.Sprintf("Successfully deleted %d jobs", cnt),
9921002
})
9931003
}

internal/graph/schema.resolvers.go

+1-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/repository/dbConnection.go

-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ func Connect(driver string, db string) {
8282
if err != nil {
8383
log.Fatal(err)
8484
}
85-
86-
startJobStartWorker()
8785
})
8886
}
8987

internal/repository/job.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,9 @@ func scanJob(row interface{ Scan(...interface{}) error }) (*schema.Job, error) {
7979
}
8080
job.RawFootprint = nil
8181

82-
// if err := json.Unmarshal(job.RawMetaData, &job.MetaData); err != nil {
83-
// return nil, err
84-
// }
85-
8682
job.StartTime = time.Unix(job.StartTimeUnix, 0)
87-
if job.Duration == 0 && job.State == schema.JobStateRunning {
83+
// Always ensure accurate duration for running jobs
84+
if job.State == schema.JobStateRunning {
8885
job.Duration = int32(time.Since(job.StartTime).Seconds())
8986
}
9087

@@ -457,6 +454,7 @@ func (r *JobRepository) AllocatedNodes(cluster string) (map[string]map[string]in
457454
return subclusters, nil
458455
}
459456

457+
// FIXME: Set duration to requested walltime?
460458
func (r *JobRepository) StopJobsExceedingWalltimeBy(seconds int) error {
461459
start := time.Now()
462460
res, err := sq.Update("job").

internal/repository/jobQuery.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ func BuildWhereClause(filter *model.JobFilter, query sq.SelectBuilder) sq.Select
170170
query = buildTimeCondition("job.start_time", filter.StartTime, query)
171171
}
172172
if filter.Duration != nil {
173-
now := time.Now().Unix() // There does not seam to be a portable way to get the current unix timestamp accross different DBs.
174-
query = query.Where("(CASE WHEN job.job_state = 'running' THEN (? - job.start_time) ELSE job.duration END) BETWEEN ? AND ?", now, filter.Duration.From, filter.Duration.To)
173+
query = buildIntCondition("job.duration", filter.Duration, query)
175174
}
176175
if filter.MinRunningFor != nil {
177176
now := time.Now().Unix() // There does not seam to be a portable way to get the current unix timestamp accross different DBs.

internal/repository/jobStartWorker.go

-83
This file was deleted.

internal/repository/repository_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func BenchmarkDB_QueryJobs(b *testing.B) {
111111
user := "mppi133h"
112112
filter.User = &model.StringInput{Eq: &user}
113113
page := &model.PageRequest{ItemsPerPage: 50, Page: 1}
114-
order := &model.OrderByInput{Field: "startTime", Order: model.SortDirectionEnumDesc}
114+
order := &model.OrderByInput{Field: "startTime", Type: "col", Order: model.SortDirectionEnumDesc}
115115

116116
b.Run("QueryJobs", func(b *testing.B) {
117117
db := setup(b)

internal/routerConfig/routes.go

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ func setupTaglistRoute(i InfoType, r *http.Request) InfoType {
182182
return i
183183
}
184184

185+
// FIXME: Lots of redundant code. Needs refactoring
185186
func buildFilterPresets(query url.Values) map[string]interface{} {
186187
filterPresets := map[string]interface{}{}
187188

0 commit comments

Comments
 (0)