Skip to content

Commit 922886b

Browse files
Merge branch 'stable-23.10' into feat/MCOL-6194-failover-conf
2 parents fdeaf57 + 5716ee0 commit 922886b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+404
-216
lines changed

.drone.jsonnet

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -396,23 +396,13 @@ local Pipeline(branch, platform, event, arch="amd64", server="10.6-enterprise",
396396
name: "dockerfile",
397397
depends_on: ["publish pkg", "publish cmapi build"],
398398
image: "alpine/git:2.49.0",
399+
volumes: [pipeline._volumes.mdb],
399400
environment: {
400-
DOCKER_BRANCH_REF: "${DRONE_SOURCE_BRANCH}",
401-
DOCKER_REF_AUX: branch_ref,
401+
DRONE_SOURCE_BRANCH: "${DRONE_SOURCE_BRANCH}",
402402
},
403403
commands: [
404-
// compute branch.
405-
'echo "$$DOCKER_REF"',
406-
'echo "$$DOCKER_BRANCH_REF"',
407-
// if DOCKER_REF is empty, try to see whether docker repository has a branch named as one we PR.
408-
'export DOCKER_REF=$${DOCKER_REF:-$$(git ls-remote https://github.com/mariadb-corporation/mariadb-columnstore-docker --h --sort origin "refs/heads/$$DOCKER_BRANCH_REF" | grep -E -o "[^/]+$$")}',
409-
'echo "$$DOCKER_REF"',
410-
// DOCKER_REF can be empty if there is no appropriate branch in docker repository.
411-
// assign what is appropriate by default.
412-
"export DOCKER_REF=$${DOCKER_REF:-$$DOCKER_REF_AUX}",
413-
'echo "$$DOCKER_REF"',
414-
"git clone --branch $$DOCKER_REF --depth 1 https://github.com/mariadb-corporation/mariadb-columnstore-docker docker",
415-
"touch docker/.secrets",
404+
"apk add bash && " +
405+
get_build_command("clone_docker_repo.sh"),
416406
],
417407
},
418408
dockerhub:: {
@@ -485,7 +475,6 @@ local Pipeline(branch, platform, event, arch="amd64", server="10.6-enterprise",
485475
MCS_IMAGE_NAME: "mariadb/enterprise-columnstore-dev:" + container_tags[0],
486476
},
487477
commands: [
488-
"echo $$DOCKER_PASSWORD | docker login --username $$DOCKER_LOGIN --password-stdin",
489478
"apk add bash && " +
490479
get_build_command("run_multi_node_mtr.sh") +
491480
" --columnstore-image-name $${MCS_IMAGE_NAME} " +

build/clone_docker_repo.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
3+
set -eo pipefail
4+
5+
SCRIPT_LOCATION=$(dirname "$0")
6+
source "$SCRIPT_LOCATION"/utils.sh
7+
8+
9+
# Determine which branch to use
10+
DOCKER_REF="${DOCKER_REF:-}"
11+
DOCKER_BRANCH_REF="${DRONE_SOURCE_BRANCH:-stable-23.10}"
12+
DOCKER_REF_AUX="stable-23.10"
13+
14+
message "Checking for docker repository branch: $DOCKER_BRANCH_REF"
15+
16+
# Try to find matching branch in docker repository
17+
if [[ -z "$DOCKER_REF" ]]; then
18+
DOCKER_REF=$(git ls-remote https://github.com/mariadb-corporation/mariadb-columnstore-docker --heads --sort origin "refs/heads/$DOCKER_BRANCH_REF" 2>/dev/null | grep -E -o "[^/]+$" || true)
19+
fi
20+
21+
# Fall back to default branch if no match found
22+
if [[ -z "$DOCKER_REF" ]]; then
23+
DOCKER_REF="$DOCKER_REF_AUX"
24+
fi
25+
26+
message "Cloning docker repository from branch: $DOCKER_REF"
27+
28+
# Remove existing docker folder if it exists to avoid git clone conflicts
29+
if [[ -d "docker" ]]; then
30+
message "Removing existing docker folder..."
31+
rm -rf docker
32+
fi
33+
34+
# Clone the docker repository
35+
git clone --branch "$DOCKER_REF" --depth 1 https://github.com/mariadb-corporation/mariadb-columnstore-docker docker
36+
37+
# Create empty .secrets file
38+
touch docker/.secrets
39+
40+
message "Docker repository cloned successfully"

build/run_multi_node_mtr.sh

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set -eo pipefail
55
SCRIPT_LOCATION=$(dirname "$0")
66
source "$SCRIPT_LOCATION"/utils.sh
77

8+
#usage example: sudo ./run_multi_node_mtr.sh --columnstore-image-name mariadb/enterprise-columnstore-dev:stable-23.10-pull-request2240 --distro rockylinux:8
89
optparse.define short=i long=columnstore-image-name desc="Name of columnstore docker image" variable=MCS_IMAGE_NAME
910
optparse.define short=d long=distro desc="Linux distro for which multinode mtr is executed" variable=DISTRO
1011
source $(optparse.build)
@@ -35,12 +36,76 @@ fi
3536

3637
message "Running multinode mtr tests..."
3738

39+
# Detect docker compose command (new syntax vs old)
40+
if command -v docker &> /dev/null && docker compose version &> /dev/null; then
41+
DOCKER_COMPOSE="docker compose"
42+
elif command -v docker-compose &> /dev/null; then
43+
DOCKER_COMPOSE="docker-compose"
44+
else
45+
error "Docker compose is not installed!"
46+
exit 1
47+
fi
48+
49+
# Handle Docker Hub authentication
50+
message "Checking Docker Hub authentication..."
51+
if [[ -n "${DOCKER_LOGIN:-}" ]] && [[ -n "${DOCKER_PASSWORD:-}" ]]; then
52+
# CI environment - use credentials from secrets
53+
message "Using Docker credentials from environment variables"
54+
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_LOGIN" --password-stdin
55+
if [[ $? -ne 0 ]]; then
56+
error "Docker login failed with provided credentials"
57+
exit 1
58+
fi
59+
else
60+
message "No Docker credentials in env variables found, checking if already logged in..."
61+
62+
# Try to verify docker login by checking auth for docker.io
63+
if docker system info 2>&1 | grep -q "Username:"; then
64+
message "Already logged in to Docker Hub"
65+
else
66+
message "Not logged in to Docker Hub"
67+
message "You need to login to Docker Hub to pull enterprise-columnstore-dev images"
68+
message ""
69+
70+
# Prompt for username
71+
read -p "Docker Hub Username: " docker_username
72+
73+
# Run docker login with username (will prompt for password)
74+
docker login -u "$docker_username"
75+
76+
if [[ $? -ne 0 ]]; then
77+
error "Docker login failed or was cancelled"
78+
exit 1
79+
fi
80+
81+
message "Docker login successful"
82+
fi
83+
fi
84+
85+
# Check if docker folder exists and has required files
86+
if [[ ! -d "docker" ]] || [[ ! -f "docker/Dockerfile" ]]; then
87+
message "Docker folder not found or incomplete, cloning mariadb-columnstore-docker repository..."
88+
"$SCRIPT_LOCATION"/clone_docker_repo.sh
89+
fi
90+
3891
cd docker
92+
93+
# Clean up any existing containers from previous runs
94+
if docker ps -a --format '{{.Names}}' | grep -q -E '^(mcs1|mcs2|mcs3)$'; then
95+
message "Found existing containers from previous run, cleaning up..."
96+
$DOCKER_COMPOSE down -v 2>/dev/null || true
97+
docker rm -f mcs1 mcs2 mcs3 2>/dev/null || true
98+
message "Cleanup completed"
99+
fi
100+
39101
cp .env_example .env
40102
sed -i "/^MCS_IMAGE_NAME=/s|=.*|=${MCS_IMAGE_NAME}|" .env
41103
sed -i "/^MAXSCALE=/s|=.*|=false|" .env
42104

43-
docker-compose up -d
105+
message "Starting containers..."
106+
$DOCKER_COMPOSE up -d
107+
108+
message "Provisioning cluster..."
44109
docker exec mcs1 provision mcs1 mcs2 mcs3
45110
docker cp ../mysql-test/columnstore mcs1:"${MTR_PATH}/suite/"
46111
docker exec -t mcs1 chown -R mysql:mysql "${MTR_PATH}"

cmapi/cmapi_server/__main__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import logging
88
import os
9+
import sys
910
import threading
1011
import time
1112
from datetime import datetime
@@ -19,21 +20,21 @@
1920
from tracing.sentry import maybe_init_sentry
2021
from tracing.traceparent_backend import TraceparentBackend
2122
from tracing.tracer import get_tracer
22-
config_cmapi_server_logging()
23-
from tracing.trace_tool import register_tracing_tools
2423

24+
config_cmapi_server_logging()
2525
from cmapi_server import helpers
26-
from cmapi_server.constants import DEFAULT_MCS_CONF_PATH, CMAPI_CONF_PATH
27-
from cmapi_server.controllers.dispatcher import dispatcher, jsonify_error, jsonify_404
26+
from cmapi_server.constants import CMAPI_CONF_PATH, DEFAULT_MCS_CONF_PATH
27+
from cmapi_server.controllers.dispatcher import dispatcher, jsonify_404, jsonify_error
2828
from cmapi_server.failover_agent import FailoverAgent
29+
from cmapi_server.invariant_checks import run_invariant_checks
2930
from cmapi_server.managers.application import AppManager
30-
from cmapi_server.managers.process import MCSProcessManager
3131
from cmapi_server.managers.certificate import CertificateManager
32-
from cmapi_server.invariant_checks import run_invariant_checks
32+
from cmapi_server.managers.process import MCSProcessManager
3333
from failover.node_monitor import NodeMonitor
3434
from failover.config import Config
3535
from mcs_node_control.models.dbrm_socket import SOCK_TIMEOUT, DBRMSocketHandler
3636
from mcs_node_control.models.node_config import NodeConfig
37+
from tracing.trace_tool import register_tracing_tools
3738

3839

3940
def worker(app):

cmapi/tracing/trace_tool.py

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,21 @@
22
CherryPy tool that uses the tracer to start a span for each request.
33
"""
44
import socket
5-
from typing import Dict
5+
import json
6+
import logging
7+
from typing import Dict, Any
68

79
import cherrypy
810

11+
from tracing.utils import swallow_exceptions
912
from tracing.tracer import get_tracer
1013

14+
logger = logging.getLogger("tracer")
15+
16+
# Limit for raw JSON string preview (in characters)
17+
_PREVIEW_MAX_CHARS = 512
18+
19+
@swallow_exceptions
1120
def _on_request_start() -> None:
1221
req = cherrypy.request
1322
tracer = get_tracer()
@@ -30,32 +39,39 @@ def _on_request_start() -> None:
3039
else:
3140
span_name = f"{method} {path}"
3241

33-
ctx = tracer.start_as_current_span(span_name, kind="SERVER")
42+
attrs = {
43+
'http.method': getattr(req, 'method', ''),
44+
'http.path': getattr(req, 'path_info', ''),
45+
'client.ip': requester_host,
46+
'instance.hostname': socket.gethostname(),
47+
}
48+
attrs.update(_record_incoming_json_preview(req))
49+
50+
ctx = tracer.start_as_current_span(span_name, kind="SERVER", attributes=attrs)
3451
span = ctx.__enter__()
35-
span.set_attribute('http.method', getattr(req, 'method', ''))
36-
span.set_attribute('http.path', getattr(req, 'path_info', ''))
37-
span.set_attribute('client.ip', requester_host)
38-
span.set_attribute('instance.hostname', socket.gethostname())
3952
safe_headers = {k: v for k, v in headers.items() if k.lower() not in {'authorization', 'x-api-key'}}
4053
span.set_attribute('sentry.incoming_headers', safe_headers)
4154
req._trace_span_ctx = ctx
4255
req._trace_span = span
4356

4457
tracer.inject_traceparent(cherrypy.response.headers)
4558

46-
59+
@swallow_exceptions
4760
def _on_request_end() -> None:
4861
req = cherrypy.request
4962
try:
5063
status_str = str(cherrypy.response.status)
5164
status_code = int(status_str.split()[0])
5265
except Exception:
5366
status_code = None
54-
tracer = get_tracer()
55-
tracer.notify_request_finished(status_code)
67+
5668
span = getattr(req, "_trace_span", None)
5769
if span is not None and status_code is not None:
5870
span.set_attribute('http.status_code', status_code)
71+
72+
tracer = get_tracer()
73+
tracer.notify_request_finished(status_code)
74+
5975
ctx = getattr(req, "_trace_span_ctx", None)
6076
if ctx is not None:
6177
try:
@@ -66,8 +82,27 @@ def _on_request_end() -> None:
6682

6783

6884
def register_tracing_tools() -> None:
69-
cherrypy.tools.trace = cherrypy.Tool("on_start_resource", _on_request_start, priority=10)
85+
cherrypy.tools.trace = cherrypy.Tool("on_start_resource", _on_request_start, priority=70)
7086
cherrypy.tools.trace_end = cherrypy.Tool("on_end_resource", _on_request_end, priority=80)
7187

88+
@swallow_exceptions
89+
def _record_incoming_json_preview(req) -> dict[str, Any]:
90+
"""If request Content-Type is JSON, attach a compact preview to span.
91+
Returns dict of span attributes to set
92+
"""
93+
attrs = {}
94+
content_type = str(getattr(req, 'headers', {}).get('Content-Type', '') or '')
95+
attrs['http.request.content_type'] = content_type
96+
if 'json' not in content_type.lower():
97+
return attrs
7298

73-
99+
parsed_json = getattr(req, 'json', None)
100+
if parsed_json is None:
101+
logger.debug('request.json is not available')
102+
return attrs
103+
normalized = json.dumps(parsed_json, ensure_ascii=False, sort_keys=True)
104+
if len(normalized) > _PREVIEW_MAX_CHARS:
105+
normalized = normalized[:_PREVIEW_MAX_CHARS] + '...<truncated>'
106+
attrs['http.request.json'] = normalized
107+
attrs['http.request.body.size'] = len(normalized)
108+
return attrs

cmapi/tracing/tracer.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ def clear_backends(self) -> None:
4646
self._backends.clear()
4747

4848
@contextmanager
49-
def start_as_current_span(self, name: str, kind: str = "INTERNAL") -> Iterator[TraceSpan]:
49+
def start_as_current_span(
50+
self,
51+
name: str,
52+
kind: str = "INTERNAL",
53+
attributes: Optional[Dict[str, Any]] = None,
54+
) -> Iterator[TraceSpan]:
5055
trace_id = _current_trace_id.get() or rand_16_hex()
5156
parent_span = _current_span_id.get()
5257
new_span_id = rand_8_hex()
@@ -63,7 +68,7 @@ def start_as_current_span(self, name: str, kind: str = "INTERNAL") -> Iterator[T
6368
trace_id=trace_id,
6469
span_id=new_span_id,
6570
parent_span_id=parent_span,
66-
attributes={"span.kind": kind, "span.name": name},
71+
attributes={"span.kind": kind, "span.name": name, **(attributes or {})},
6772
tracer=self,
6873
)
6974

0 commit comments

Comments
 (0)