Skip to content

Commit fa9dd0c

Browse files
committed
Add extended version info
This change introduces a new CLI option to report the verions of scylla-bench and gocql driver.
1 parent 65121c1 commit fa9dd0c

File tree

4 files changed

+236
-12
lines changed

4 files changed

+236
-12
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ require (
1717
sigs.k8s.io/yaml v1.3.0 // indirect
1818
)
1919

20-
replace github.com/gocql/gocql => github.com/scylladb/gocql v1.14.1
20+
replace github.com/gocql/gocql => github.com/scylladb/gocql v1.14.4

go.sum

+2-4
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
3434
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3535
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3636
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
37-
github.com/scylladb/gocql v1.12.1-0.20240207140227-3c32c6cd75e5 h1:XoLZb7wy5fuu42o2dJurb5cQ3G/0xPVSB27LaBDLPkk=
38-
github.com/scylladb/gocql v1.12.1-0.20240207140227-3c32c6cd75e5/go.mod h1:ZLEJ0EVE5JhmtxIW2stgHq/v1P4fWap0qyyXSKyV8K0=
39-
github.com/scylladb/gocql v1.14.1 h1:ZO7+VWWn1O/dW9lYNkGs+ePOayiRiPiXjSX0A7KRi1o=
40-
github.com/scylladb/gocql v1.14.1/go.mod h1:ZLEJ0EVE5JhmtxIW2stgHq/v1P4fWap0qyyXSKyV8K0=
37+
github.com/scylladb/gocql v1.14.4 h1:MhevwCfyAraQ6RvZYFO3pF4Lt0YhvQlfg8Eo2HEqVQA=
38+
github.com/scylladb/gocql v1.14.4/go.mod h1:ZLEJ0EVE5JhmtxIW2stgHq/v1P4fWap0qyyXSKyV8K0=
4139
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
4240
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
4341
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=

internal/version/version.go

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package version
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"runtime/debug"
8+
"strings"
9+
"time"
10+
)
11+
12+
var (
13+
// Default version values; can be overridden via ldflags
14+
version = "dev"
15+
commit = "unknown"
16+
date = "unknown"
17+
)
18+
19+
type ComponentInfo struct {
20+
Version string `json:"version"`
21+
CommitDate string `json:"commit_date"`
22+
CommitSHA string `json:"commit_sha"`
23+
}
24+
25+
type VersionInfo struct {
26+
ScyllaBench ComponentInfo `json:"scylla-bench"`
27+
Driver ComponentInfo `json:"scylla-driver"`
28+
}
29+
30+
type githubRelease struct {
31+
TagName string `json:"tag_name"`
32+
CreatedAt time.Time `json:"created_at"`
33+
}
34+
35+
type githubTag struct {
36+
Object struct {
37+
SHA string `json:"sha"`
38+
} `json:"object"`
39+
}
40+
41+
const (
42+
gocqlPackage = "github.com/gocql/gocql"
43+
githubTimeout = 5 * time.Second
44+
userAgent = "scylla-bench (github.com/scylladb/scylla-bench)"
45+
)
46+
47+
var githubAPIBaseURL = "https://api.github.com"
48+
49+
// Performs an HTTP GET request to fetch release data in JSON format from GitHub
50+
func getJSON(client *http.Client, url string, target interface{}) error {
51+
req, err := http.NewRequest("GET", url, nil)
52+
if err != nil {
53+
return fmt.Errorf("failed to create request: %w", err)
54+
}
55+
req.Header.Set("User-Agent", userAgent)
56+
resp, err := client.Do(req)
57+
if err != nil {
58+
return fmt.Errorf("request failed: %w", err)
59+
}
60+
defer resp.Body.Close()
61+
if resp.StatusCode != http.StatusOK {
62+
return fmt.Errorf("unexpected status %d", resp.StatusCode)
63+
}
64+
if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
65+
return fmt.Errorf("failed to decode JSON: %w", err)
66+
}
67+
return nil
68+
}
69+
70+
// Retrieves the release date and commit SHA for a given scylladb repository and version from GitHub
71+
func getReleaseInfo(repo, version string) (date, sha string, err error) {
72+
client := &http.Client{Timeout: githubTimeout}
73+
74+
// Fetch releases
75+
releasesURL := fmt.Sprintf("%s/repos/scylladb/%s/releases", githubAPIBaseURL, repo)
76+
var releases []githubRelease
77+
if err := getJSON(client, releasesURL, &releases); err != nil {
78+
return "", "", fmt.Errorf("failed to fetch releases: %w", err)
79+
}
80+
81+
// Find matching release
82+
cleanVersion := strings.TrimPrefix(version, "v")
83+
var releaseDate, tagName string
84+
for _, release := range releases {
85+
if strings.TrimPrefix(release.TagName, "v") == cleanVersion {
86+
releaseDate = release.CreatedAt.Format(time.RFC3339)
87+
tagName = release.TagName
88+
break
89+
}
90+
}
91+
if tagName == "" {
92+
return "", "", fmt.Errorf("release %s not found", version)
93+
}
94+
95+
// Fetch tag info to get the commit SHA
96+
tagURL := fmt.Sprintf("%s/repos/scylladb/%s/git/refs/tags/%s", githubAPIBaseURL, repo, tagName)
97+
var tag githubTag
98+
if err := getJSON(client, tagURL, &tag); err != nil {
99+
return releaseDate, "", fmt.Errorf("failed to fetch tag info: %w", err)
100+
}
101+
102+
return releaseDate, tag.Object.SHA, nil
103+
}
104+
105+
// Retrieves scylla-bench version info from build info
106+
func readMainBuildInfo() (ver, sha, buildDate string) {
107+
ver = version
108+
sha = commit
109+
buildDate = date
110+
if info, ok := debug.ReadBuildInfo(); ok {
111+
for _, setting := range info.Settings {
112+
switch setting.Key {
113+
case "vcs.revision":
114+
if sha == "unknown" {
115+
sha = setting.Value
116+
}
117+
case "vcs.time":
118+
if buildDate == "unknown" {
119+
buildDate = setting.Value
120+
}
121+
}
122+
}
123+
if ver == "dev" {
124+
if info.Main.Version != "" {
125+
ver = info.Main.Version
126+
} else {
127+
ver = "(devel)"
128+
}
129+
}
130+
}
131+
return
132+
}
133+
134+
// Retrieves scylla-gocql-driver version info from build info
135+
func getDriverInfo() ComponentInfo {
136+
comp := ComponentInfo{
137+
Version: "unknown",
138+
CommitSHA: "unknown",
139+
CommitDate: "unknown",
140+
}
141+
if info, ok := debug.ReadBuildInfo(); ok {
142+
for _, d := range info.Deps {
143+
if d.Path == gocqlPackage {
144+
comp.Version = d.Version
145+
if d.Replace != nil {
146+
comp.Version = d.Replace.Version
147+
if dDate, dSHA, err := getReleaseInfo("gocql", comp.Version); err == nil {
148+
comp.CommitDate = dDate
149+
comp.CommitSHA = dSHA
150+
} else {
151+
comp.CommitSHA = "unknown"
152+
comp.CommitDate = "unknown"
153+
}
154+
} else {
155+
comp.CommitSHA = "upstream release"
156+
comp.CommitDate = "unknown"
157+
}
158+
break
159+
}
160+
}
161+
}
162+
return comp
163+
}
164+
165+
// Returns the version info for scylla-bench and scylla-gocql-driver
166+
func GetVersionInfo() VersionInfo {
167+
ver, sha, buildDate := readMainBuildInfo()
168+
driverInfo := getDriverInfo()
169+
return VersionInfo{
170+
ScyllaBench: ComponentInfo{
171+
Version: ver,
172+
CommitDate: buildDate,
173+
CommitSHA: sha,
174+
},
175+
Driver: driverInfo,
176+
}
177+
}
178+
179+
// Returns a human-readable string with version info
180+
func (v VersionInfo) FormatHuman() string {
181+
return fmt.Sprintf(`scylla-bench:
182+
version: %s
183+
commit sha: %s
184+
commit date: %s
185+
scylla-gocql-driver:
186+
version: %s
187+
commit sha: %s
188+
commit date: %s`,
189+
v.ScyllaBench.Version,
190+
v.ScyllaBench.CommitSHA,
191+
v.ScyllaBench.CommitDate,
192+
v.Driver.Version,
193+
v.Driver.CommitSHA,
194+
v.Driver.CommitDate,
195+
)
196+
}
197+
198+
// Returns a JSON-formatted string with version info
199+
func (v VersionInfo) FormatJSON() (string, error) {
200+
data, err := json.MarshalIndent(v, "", " ")
201+
if err != nil {
202+
return "", fmt.Errorf("failed to marshal version info to JSON: %w", err)
203+
}
204+
return string(data), nil
205+
}

main.go

+28-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"sync/atomic"
1212
"time"
1313

14+
"github.com/scylladb/scylla-bench/internal/version"
1415
"github.com/scylladb/scylla-bench/pkg/results"
1516

1617
"github.com/gocql/gocql"
@@ -118,13 +119,13 @@ func PrepareDatabase(session *gocql.Session, replicationFactor int) {
118119
Query(session, fmt.Sprintf("CREATE KEYSPACE IF NOT EXISTS %s WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'replication_factor' : %d }", keyspaceName, replicationFactor))
119120

120121
switch mode {
121-
case "counter_update":
122-
fallthrough
123-
case "counter_read":
124-
Query(session, "CREATE TABLE IF NOT EXISTS "+keyspaceName+"."+counterTableName+
125-
" (pk bigint, ck bigint, c1 counter, c2 counter, c3 counter, c4 counter, c5 counter, PRIMARY KEY(pk, ck)) WITH compression = { }")
126-
default:
127-
Query(session, "CREATE TABLE IF NOT EXISTS "+keyspaceName+"."+tableName+" (pk bigint, ck bigint, v blob, PRIMARY KEY(pk, ck)) WITH compression = { }")
122+
case "counter_update":
123+
fallthrough
124+
case "counter_read":
125+
Query(session, "CREATE TABLE IF NOT EXISTS "+keyspaceName+"."+counterTableName+
126+
" (pk bigint, ck bigint, c1 counter, c2 counter, c3 counter, c4 counter, c5 counter, PRIMARY KEY(pk, ck)) WITH compression = { }")
127+
default:
128+
Query(session, "CREATE TABLE IF NOT EXISTS "+keyspaceName+"."+tableName+" (pk bigint, ck bigint, v blob, PRIMARY KEY(pk, ck)) WITH compression = { }")
128129

129130
}
130131
if truncateTable {
@@ -274,6 +275,9 @@ func main() {
274275

275276
datacenter string
276277
rack string
278+
279+
showVersion bool
280+
showJSONVersion bool
277281
)
278282

279283
flag.StringVar(&mode, "mode", "", "operating mode: write, read, counter_update, counter_read, scan")
@@ -354,6 +358,8 @@ func main() {
354358
"If it is set to '0' then no limit for number of errors is applied.")
355359

356360
flag.StringVar(&cloudConfigPath, "cloud-config-path", "", "set the cloud config bundle")
361+
flag.BoolVar(&showVersion, "version", false, "show versions information of the tool and driver (human-readable)")
362+
flag.BoolVar(&showJSONVersion, "version-json", false, "show versions information of the tool and driver in JSON format")
357363

358364
flag.Parse()
359365
counterTableName = "test_counters"
@@ -363,6 +369,21 @@ func main() {
363369
flag.PrintDefaults()
364370
}
365371

372+
if showVersion || showJSONVersion {
373+
info := version.GetVersionInfo()
374+
if showJSONVersion {
375+
jsonOutput, err := info.FormatJSON()
376+
if err != nil {
377+
fmt.Fprintf(os.Stderr, "error formatting version info: %v\n", err)
378+
os.Exit(1)
379+
}
380+
fmt.Println(jsonOutput)
381+
} else {
382+
fmt.Println(info.FormatHuman())
383+
}
384+
os.Exit(0)
385+
}
386+
366387
if mode == "" {
367388
log.Fatal("test mode needs to be specified")
368389
}

0 commit comments

Comments
 (0)