Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
51aabb9
Adjusted logic
pavelnemirovsky May 12, 2021
8d905da
Error handling
pavelnemirovsky May 12, 2021
669e5a7
tests
pavelnemirovsky May 12, 2021
881b17a
Adjust
pavelnemirovsky May 13, 2021
fc7db12
session_id
pavelnemirovsky May 13, 2021
444a437
test adjustment
pavelnemirovsky May 13, 2021
4f7a4e8
session_timeout logic
pavelnemirovsky May 21, 2021
2ebaa88
session_timeout tests
pavelnemirovsky May 21, 2021
14fc89f
header test
pavelnemirovsky May 21, 2021
26ca1f5
cleaning unused code
pavelnemirovsky May 21, 2021
dce7872
handling session_id verification
pavelnemirovsky May 21, 2021
456d694
Ability to build version under Docker (Native go build doesn't work d…
pavelnemirovsky May 23, 2021
eca0b6c
Error handling in Makefile
pavelnemirovsky May 24, 2021
eb5aa66
Merge https://github.com/Vertamedia/chproxy
pavelnemirovsky May 24, 2021
4304395
Bump to newer go + make sure static linking works correctly
pavelnemirovsky May 24, 2021
e5d9dca
Session_id typo fix
pavelnemirovsky Jun 3, 2021
15a7609
Adjust tests for session-name and session-timeout
pavelnemirovsky Jun 4, 2021
7ef6f48
Merge remote-tracking branch 'origin/master'
pavelnemirovsky Nov 16, 2023
b3fb12b
Adjust tests for session-name and session-timeout
pavelnemirovsky Nov 16, 2023
f1e4b68
Adjust tests for session-name and session-timeout
pavelnemirovsky Nov 17, 2023
028c67d
Adjust tests for session-name and session-timeout
pavelnemirovsky Nov 21, 2023
4798d96
FIPS and Session_ID Documentation
pavelnemirovsky Dec 17, 2023
d3f1dd8
chore: update dockerfile, add tests for dockerfile
Oct 22, 2024
7d7fc26
chore: remove more vulnerabilities
Nov 12, 2024
8545d51
Update go.mod
vsirmbard Dec 25, 2024
bfeec48
Update go.sum
vsirmbard Dec 25, 2024
c4a408c
Go 1.22 Fix Action
pavelnemirovsky Dec 25, 2024
792bae7
Go 1.22 Fix Action
pavelnemirovsky Dec 25, 2024
f4147ab
Merge pull request #1 from pavelnemirovsky/Update-net-and-crypto-pack…
pavelnemirovsky Dec 25, 2024
03001bc
Merge branch 'master' into master
pavelnemirovsky Dec 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions .github/workflows/go-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.22
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.22

- name: Build
run: go build -v ./...
- name: Build
run: go build -v ./...

- name: Test
run: go test -v ./...

- name: Update coverage report
uses: ncruces/go-coverage-report@21fa4b59396f242b81896a3cd212a463589b6742
with:
report: 'false'
chart: 'true'
amend: 'false'
- name: Test
run: go test -v ./...

- name: Update coverage report
uses: ncruces/go-coverage-report@21fa4b59396f242b81896a3cd212a463589b6742
with:
report: 'false'
chart: 'true'
amend: 'false'
3 changes: 1 addition & 2 deletions .github/workflows/golangci-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.57.2

version: v1.57.2
3 changes: 1 addition & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,4 @@ jobs:
env:
BUILD_TAG: 'latest'
GOPATH: ${{ env.GOPATH }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
# Examples data directories
examples/*/resources/chproxy/data
examples/*/resources/clickhouse/data
examples/*/resources/clickhouse/config/*-preprocessed.xml
examples/*/resources/clickhouse/config/*-preprocessed.xml
/config.yml
21 changes: 16 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
FROM debian
ARG GO_VERSION=1.22.7
FROM golang:${GO_VERSION}-alpine AS build

RUN apt update && apt install -y ca-certificates curl
RUN apk add --no-cache --update zstd-static zstd-dev make gcc musl-dev git libc6-compat && \
apk del openssl && \
apk add --no-cache openssl=3.3.2-r1

COPY chproxy /
RUN mkdir -p /go/src/github.com/contentsquare/chproxy
WORKDIR /go/src/github.com/contentsquare/chproxy
COPY . ./
ARG EXT_BUILD_TAG
ENV EXT_BUILD_TAG=${EXT_BUILD_TAG}
RUN make release-build
RUN ls -al /go/src/github.com/contentsquare/chproxy

EXPOSE 9090
FROM alpine
RUN apk add --no-cache curl ca-certificates
COPY --from=build /go/src/github.com/contentsquare/chproxy/chproxy* /

ENTRYPOINT ["/chproxy"]
ENTRYPOINT [ "/chproxy" ]
CMD [ "--help" ]
44 changes: 44 additions & 0 deletions Dockerfile_boringcrypto
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
ARG UBUNTU_IMAGE=ubuntu:20.04
FROM ${UBUNTU_IMAGE} AS build

ENV GOPATH=/gocode
ENV PATH=$PATH:$GOPATH/bin
ENV GO_VERSION=1.22

RUN mkdir /src
WORKDIR /src

# golang
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
apt-utils \
software-properties-common \
gcc \
libc-dev \
&& add-apt-repository -y ppa:longsleep/golang-backports \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
golang-$GO_VERSION-go \
golang-golang-x-tools \
&& apt-get autoremove -y \
&& apt-get remove -y \
apt-utils \
software-properties-common

# Create symbolic link
RUN ln -s /usr/lib/go-$GO_VERSION /gocode

# tools
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
git \
make \
tzdata \
curl \
ca-certificates

FROM build

# Build chproxy
COPY . ./
ARG EXT_BUILD_TAG
ENV GOEXPERIMENT=boringcrypto
RUN make release-build
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,19 @@ clean:
release-build:
@echo "Ver: $(BUILD_TAG), OPTS: $(BUILD_OPTS)"
GOOS=linux GOARCH=amd64 go build $(BUILD_OPTS)
rm chproxy-linux-amd64-*.tar.gz || true
tar czf chproxy-linux-amd64-$(BUILD_TAG).tar.gz chproxy
rm chproxy-linux-amd64-*.tar.gz

release: format lint test clean release-build
@echo "Ver: $(BUILD_TAG), OPTS: $(BUILD_OPTS)"
tar czf chproxy-linux-amd64-$(BUILD_TAG).tar.gz chproxy

release-build-docker:
@echo "Ver: $(BUILD_TAG)"
@DOCKER_BUILDKIT=1 docker build --target build --build-arg EXT_BUILD_TAG=$(BUILD_TAG) --progress plain -t chproxy-build .
@docker run --rm --entrypoint "/bin/sh" -v $(CURDIR):/host chproxy-build -c "/bin/cp /go/src/github.com/contentsquare/chproxy/*.tar.gz /host"
@DOCKER_BUILDKIT=1 docker build -f Dockerfile --target build --build-arg EXT_BUILD_TAG=$(BUILD_TAG) --progress plain -t chproxy-build .
@docker run --rm --entrypoint "/bin/sh" -v $(CURDIR):/host chproxy-build -c "/bin/cp chproxy-linux-*-*.tar.gz /host"

release-build-docker-fips:
@echo "Ver: $(BUILD_TAG)"
@DOCKER_BUILDKIT=1 docker build -f Dockerfile_boringcrypto --build-arg EXT_BUILD_TAG=$(BUILD_TAG)-fips --build-arg EXT_BUILD_OPTS="-tags fips" --progress plain -t chproxy-build .
@docker run --rm --entrypoint "/bin/sh" -v $(CURDIR):/host chproxy-build -c "/bin/cp /src/chproxy-*.tar.gz /host"
67 changes: 67 additions & 0 deletions dockerfile_version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"bufio"
"os"
"regexp"
"strings"
"testing"
)

func getVersionFromFile(filename string, searchPhrase string) (string, error) {
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()

scanner := bufio.NewScanner(file)
re := regexp.MustCompile(searchPhrase) // Regex to capture Go version
for scanner.Scan() {
line := scanner.Text()
matches := re.FindStringSubmatch(line)
if len(matches) > 1 {
return matches[1], nil
}
}

return "", scanner.Err()
}

// Test function to check if Go version in go.mod matches Dockerfile
func TestGoVersionMatching(t *testing.T) {
goModVersionSearchPhrase := `^go\s+(\d+\.\d+)`
goModVersion, err := getVersionFromFile("go.mod", goModVersionSearchPhrase)
if err != nil {
t.Fatalf("Error getting Go version from go.mod: %v", err)
}

dockerFileVersionSearchPhrase := "GO_VERSION=(.*)"
dockerfileVersion, err := getVersionFromFile("Dockerfile", dockerFileVersionSearchPhrase)
if err != nil {
t.Fatalf("Error getting Go version from Dockerfile: %v", err)
}

if !strings.HasPrefix(dockerfileVersion, goModVersion) {
t.Errorf("Go version mismatch: go.mod (%s), Dockerfile (%s)", goModVersion, dockerfileVersion)
}
}

// Test function to check if Go version in go.mod matches Dockerfile_boringcrypto
func TestGoVersionMatchingBoringCrypto(t *testing.T) {
goModVersionSearchPhrase := `^go\s+(\d+\.\d+)`
goModVersion, err := getVersionFromFile("go.mod", goModVersionSearchPhrase)
if err != nil {
t.Fatalf("Error getting Go version from go.mod: %v", err)
}

dockerFileVersionSearchPhrase := "GO_VERSION=(.*)"
dockerfileVersion, err := getVersionFromFile("Dockerfile_boringcrypto", dockerFileVersionSearchPhrase)
if err != nil {
t.Fatalf("Error getting Go version from Dockerfile_boringcrypto: %v", err)
}

if !strings.HasPrefix(dockerfileVersion, goModVersion) {
t.Errorf("Go version mismatch: go.mod (%s), Dockerfile (%s)", goModVersion, dockerfileVersion)
}
}
8 changes: 8 additions & 0 deletions docs/src/content/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ Chproxy is an HTTP proxy and load balancer for [ClickHouse](https://ClickHouse.y
- Exposes various useful [metrics](/configuration/metrics) in [Prometheus text format](https://prometheus.io/docs/instrumenting/exposition_formats/).
- Configuration may be updated without restart - just send `SIGHUP` signal to `chproxy` process.
- Easy to manage and run - just pass config file path to a single `chproxy` binary.
- Facilitates session affinity through `session_id` mapping, guaranteeing requests from the same user session are routed to the same upstream server (It is useful if one application server performs an initial processing step and stores the results in a temporary table; other servers can efficiently access and utilize that data by reaching the same server where the data is.)
- Service can be built to use only cryptographic algorithms approved by the Federal Information Processing Standard (FIPS) 140-2, making it suitable for processing sensitive government data.
```bash
-- to build regular artifact
make release-build-docker
-- to build artifact with FIPS support relying on Borring Crypto Module
make release-build-docker-fips:
```
- Easy to [configure](https://github.com/contentsquare/chproxy/blob/master/config/examples/simple.yml):
```yml
server:
Expand Down
5 changes: 5 additions & 0 deletions fips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build fips

package main

import _ "crypto/tls/fipsonly"
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.22

require (
github.com/alicebob/miniredis/v2 v2.21.0
github.com/coreos/go-systemd/v22 v22.5.0
github.com/google/go-cmp v0.5.7
github.com/klauspost/compress v1.15.11
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
Expand All @@ -31,7 +30,7 @@ require (
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
Expand Down
7 changes: 2 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -38,7 +36,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -141,8 +138,8 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
31 changes: 23 additions & 8 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func TestServe(t *testing.T) {
"testdata/https.cache.yml",
func(t *testing.T) {
// do request which response must be cached
queryURLParam := "SELECT * FROM system.numbers"
queryURLParam := "select * from system.numbers"
queryBody := "LIMIT 10"
expectedQuery := queryURLParam + "\n" + queryBody
buf := bytes.NewBufferString(queryBody)
Expand Down Expand Up @@ -443,21 +443,36 @@ func TestServe(t *testing.T) {
startHTTP,
},
{
"http POST request with session id",
"http POST request with session_id and session_timeout",
"testdata/http-session-id.yml",
func(t *testing.T) {
sessionName := "name"
sessionTimeout := 900
req, err := http.NewRequest("POST",
"http://127.0.0.1:9090/?query_id=45395792-a432-4b92-8cc9-536c14e1e1a9&extremes=0&session_id=default-session-id233",
bytes.NewBufferString("SELECT * FROM system.numbers LIMIT 10"))
"http://127.0.0.1:9090/?query_id=45395792-a432-4b92-8cc9-536c14e1e1a9&extremes=0&session_id="+sessionName+"&session_timeout="+strconv.Itoa(sessionTimeout),
bytes.NewBufferString("select * from system.numbers LIMIT 10"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;") // This makes it work

checkErr(t, err)
resp, err := http.DefaultClient.Do(req)
checkErr(t, err)

if resp.StatusCode != http.StatusOK || resp.StatusCode != http.StatusOK && resp.Header.Get("X-Clickhouse-Server-Session-Id") == "" {
if resp.StatusCode != http.StatusOK {
t.Fatalf("unexpected status code: %d; expected: %d", resp.StatusCode, http.StatusOK)
}

// verify correctness of session_id
_sessionName := resp.Header.Get("X-Clickhouse-Server-Session-Id")
if _sessionName != sessionName {
t.Fatalf("unexpected value of X-Clickhouse-Server-Session-Id: %s; expected: %s", _sessionName, sessionName)
}

// verify correctness of session_id
_sessionTimeout, _ := strconv.Atoi(resp.Header.Get("X-Clickhouse-Server-Session-Timeout"))
if _sessionTimeout != sessionTimeout {
t.Fatalf("unexpected value of X-Clickhouse-Server-Session-Timeout: %d; expected: %d", _sessionTimeout, sessionTimeout)
}

resp.Body.Close()
},
startHTTP,
Expand Down Expand Up @@ -548,7 +563,7 @@ func TestServe(t *testing.T) {
func(t *testing.T) {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
_, err := zw.Write([]byte("SELECT * FROM system.numbers LIMIT 10"))
_, err := zw.Write([]byte("select * from system.numbers LIMIT 10"))
checkErr(t, err)
zw.Close()
req, err := http.NewRequest("POST", "http://127.0.0.1:9090", &buf)
Expand All @@ -569,7 +584,7 @@ func TestServe(t *testing.T) {
"http POST request",
"testdata/http.yml",
func(t *testing.T) {
buf := bytes.NewBufferString("SELECT * FROM system.numbers LIMIT 10")
buf := bytes.NewBufferString("select * from system.numbers LIMIT 10")
req, err := http.NewRequest("POST", "http://127.0.0.1:9090", buf)
checkErr(t, err)
resp, err := http.DefaultClient.Do(req)
Expand All @@ -587,7 +602,7 @@ func TestServe(t *testing.T) {
func(t *testing.T) {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
_, err := zw.Write([]byte("SELECT * FROM system.numbers LIMIT 1000"))
_, err := zw.Write([]byte("select * from system.numbers LIMIT 1000"))
checkErr(t, err)
zw.Close()
req, err := http.NewRequest("POST", "http://127.0.0.1:9090", &buf)
Expand Down
5 changes: 5 additions & 0 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ func (rp *reverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("X-ClickHouse-Server-Session-Id", s.sessionId)
}

// publish session_timeout if needed
if s.sessionId != "" {
rw.Header().Set("X-ClickHouse-Server-Session-Timeout", strconv.Itoa(s.sessionTimeout))
}

q, shouldReturnFromCache, err := shouldRespondFromCache(s, origParams, req)
if err != nil {
respondWith(srw, err, http.StatusBadRequest)
Expand Down