Skip to content

Commit 487a92b

Browse files
authored
[rqd/cicd] Replace python/rqd by rust/rqd on docker stack (AcademySoftwareFoundation#2227)
As previously communicated, python/rqd is now deprecated and it's being officially replaced by rust/rqd on docker-composed and on the release pipeline. --------- Signed-off-by: Diego Tavares <dtavares@imageworks.com>
1 parent ee9af69 commit 487a92b

7 files changed

Lines changed: 110 additions & 42 deletions

File tree

.github/workflows/packaging-pipeline.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,12 @@ jobs:
189189
include:
190190
- component: cuebot
191191
NAME: Cuebot
192+
DOCKERFILE: cuebot/Dockerfile
192193
ARTIFACTS: cuebot-${BUILD_ID}-all.jar opencue-cuebot-${BUILD_ID}-1.noarch.rpm
193194

194195
- component: rqd
195196
NAME: RQD
197+
DOCKERFILE: rust/Dockerfile.rqd
196198

197199
name: Build ${{ matrix.NAME }}
198200
runs-on: ubuntu-22.04
@@ -243,7 +245,7 @@ jobs:
243245
- name: Build Docker image
244246
run: |
245247
image_name="opencuebuild/${{ matrix.component }}:${BUILD_ID}"
246-
docker buildx build . -f ${{ matrix.component }}/Dockerfile -t ${image_name} \
248+
docker buildx build . -f ${{ matrix.DOCKERFILE }} -t ${image_name} \
247249
--build-arg OPENCUE_PROTO_PACKAGE_PATH="${{ needs.build_opencue_packages.outputs.opencue_proto_path }}" \
248250
--build-arg OPENCUE_RQD_PACKAGE_PATH="${{ needs.build_opencue_packages.outputs.opencue_rqd_path }}" \
249251
--build-arg OPENCUE_PYCUE_PACKAGE_PATH="${{ needs.build_opencue_packages.outputs.opencue_pycue_path }}" \

ci/run_integration_test.sh

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -245,22 +245,12 @@ main() {
245245

246246
log INFO "Building Cuebot image..."
247247
docker build -t opencue/cuebot -f cuebot/Dockerfile . &>"${TEST_LOGS}/docker-build-cuebot.log"
248-
if [[ ! -e "${OPENCUE_PROTO_PACKAGE_PATH}" ]]; then
249-
rm -rf proto/dist/*.*
250-
python -m build proto
251-
OPENCUE_PROTO_PACKAGE_PATH=$(ls -1 proto/dist/*.tar.gz)
252-
export OPENCUE_PROTO_PACKAGE_PATH
253-
fi
254-
if [[ ! -e "${OPENCUE_RQD_PACKAGE_PATH}" ]]; then
255-
rm -rf rqd/dist/*.*
256-
python -m build rqd
257-
OPENCUE_RQD_PACKAGE_PATH=$(ls -1 rqd/dist/*.tar.gz)
258-
export OPENCUE_RQD_PACKAGE_PATH
259-
fi
260248
log INFO "Building RQD image..."
261-
docker build --build-arg OPENCUE_PROTO_PACKAGE_PATH="${OPENCUE_PROTO_PACKAGE_PATH}" \
262-
--build-arg OPENCUE_RQD_PACKAGE_PATH="${OPENCUE_RQD_PACKAGE_PATH}" \
263-
-t opencue/rqd -f rqd/Dockerfile . &>"${TEST_LOGS}/docker-build-rqd.log"
249+
if ! docker build -t opencue/rqd -f rust/Dockerfile.rqd . &>"${TEST_LOGS}/docker-build-rqd.log"; then
250+
log ERROR "RQD Docker build failed. Build log:"
251+
cat "${TEST_LOGS}/docker-build-rqd.log"
252+
exit 1
253+
fi
264254

265255
# Pre-create bind-mount directories so Docker doesn't create them as root
266256
mkdir -p "${HOME}/.opencue/sessions"

docker-compose.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# OpenCue Docker Compose Configuration
22
#
3-
# By default, only the core services are enabled (db, flyway, cuebot, rqd).
3+
# By default, only the core services are enabled (db, flyway, cuebot, rqd (Rust)).
44
# Uncomment the optional sections to enable additional functionality:
55
#
66
# Profiles:
@@ -190,10 +190,10 @@ services:
190190
rqd:
191191
build:
192192
context: ./
193-
dockerfile: ./rqd/Dockerfile
193+
dockerfile: ./rust/Dockerfile.rqd
194194
environment:
195-
- PYTHONUNBUFFERED=1
196-
- CUEBOT_HOSTNAME=cuebot
195+
- OPENRQD__GRPC__CUEBOT_ENDPOINTS=cuebot:8443
196+
- OPENRQD__MACHINE__USE_IP_AS_HOSTNAME=true
197197
depends_on:
198198
cuebot:
199199
condition: service_healthy

docs/_docs/getting-started/deploying-rqd.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,26 @@ Make sure you also complete the following steps:
8686
1. On macOS you might also need to
8787
[increase Docker's RAM limit](https://docs.docker.com/docker-for-mac/#advanced).
8888

89-
### Option 1: Downloading and running RQD from DockerHub
89+
### Option 1: Building and running Rust RQD from source (Recommended)
9090

91-
To download and run the pre-built Docker image from DockerHub:
91+
To build and run the Rust RQD Docker image from source:
9292

9393
```shell
94-
docker pull opencue/rqd
95-
docker run -td --name rqd01 --env CUEBOT_HOSTNAME=${CUEBOT_HOSTNAME} --volume "${CUE_FS_ROOT}:${CUE_FS_ROOT}" --add-host host.docker.internal:host-gateway opencue/rqd
94+
docker build -t opencue/rqd -f rust/Dockerfile.rqd rust/
95+
docker run -td --name rqd01 --env OPENRQD__GRPC__CUEBOT_ENDPOINTS=${CUEBOT_HOSTNAME}:8443 --volume "${CUE_FS_ROOT}:${CUE_FS_ROOT}" --add-host host.docker.internal:host-gateway opencue/rqd
9696
```
9797

98-
### Option 2: Building and running RQD from source
98+
### Option 2 (Legacy): Downloading and running Python RQD from DockerHub
9999

100-
To build and run the RQD Docker image from source:
100+
> **Note:** The Python RQD is deprecated. Consider using the Rust RQD (Option 1) for improved performance and resource efficiency.
101+
102+
To download and run the pre-built Python RQD Docker image from DockerHub:
101103

102104
```shell
103-
docker build -t opencue/rqd -f rqd/Dockerfile .
105+
docker pull opencue/rqd
104106
docker run -td --name rqd01 --env CUEBOT_HOSTNAME=${CUEBOT_HOSTNAME} --volume "${CUE_FS_ROOT}:${CUE_FS_ROOT}" --add-host host.docker.internal:host-gateway opencue/rqd
105107
```
106108

107-
<!-- - **In both Option 1 and 2**, if running the RQD container in your local machine, use the `--add-host` flag on the `docker run` command as follows:
108-
109-
```shell
110-
docker run -td --name rqd01 --env CUEBOT_HOSTNAME=${CUEBOT_HOSTNAME} --volume "${CUE_FS_ROOT}:${CUE_FS_ROOT}" --add-host host.docker.internal:host-gateway opencue/rqd
111-
``` -->
112-
113109
### Option 3: Installing from pypi
114110

115111
To install from the published pypi release:

rust/Dockerfile.rqd

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Multi-stage Dockerfile for OpenCue Rust RQD
2+
3+
# Build stage
4+
FROM rust:1.88-bookworm AS builder
5+
6+
# Install build dependencies
7+
RUN apt-get update && apt-get install -y \
8+
protobuf-compiler \
9+
libprotobuf-dev \
10+
pkg-config \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
# Create app directory
14+
WORKDIR /build
15+
16+
# Copy workspace files
17+
COPY rust/Cargo.toml ./
18+
COPY rust/Cargo.lock* ./
19+
20+
# Copy all crate directories
21+
COPY rust/crates ./crates
22+
23+
# Remove symlink and copy proto files from repo root
24+
RUN rm ./crates/opencue-proto/src/protos
25+
COPY proto/src ./crates/opencue-proto/src/protos
26+
27+
# Build RQD in release mode
28+
RUN cargo build --release -p rqd
29+
30+
# Runtime stage
31+
FROM debian:bookworm-slim
32+
33+
# Install runtime dependencies
34+
RUN apt-get update && apt-get install -y \
35+
ca-certificates \
36+
libx11-6 \
37+
&& rm -rf /var/lib/apt/lists/*
38+
39+
# Create app user
40+
RUN useradd -m -u 1000 -s /bin/bash rqd
41+
42+
# Create necessary directories
43+
RUN mkdir -p /app/resources && chown -R rqd:rqd /app
44+
45+
WORKDIR /app
46+
47+
# Copy the built binary from builder stage
48+
COPY --from=builder /build/target/release/openrqd /app/openrqd
49+
50+
# Copy resources
51+
COPY --from=builder /build/crates/rqd/resources /app/resources
52+
53+
# RQD gRPC server
54+
EXPOSE 8444
55+
56+
# Run RQD
57+
ENTRYPOINT ["/app/openrqd"]
58+
CMD []

rust/crates/rqd/src/config/mod.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::config::error::RqdConfigError;
1616
use bytesize::ByteSize;
1717
use config::{Config as ConfigBase, Environment, File};
1818
use lazy_static::lazy_static;
19-
use serde::{Deserialize, Serialize};
19+
use serde::{Deserialize, Deserializer, Serialize};
2020
use std::{collections::HashMap, env, fs, path::Path, time::Duration};
2121

2222
static DEFAULT_CONFIG_FILE: &str = "~/.local/share/rqd.yaml";
@@ -47,11 +47,30 @@ impl Default for LoggingConfig {
4747
}
4848
}
4949

50+
/// Deserializes a value that can be either a single comma-separated string or a sequence of strings.
51+
fn string_or_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
52+
where
53+
D: Deserializer<'de>,
54+
{
55+
#[derive(Deserialize)]
56+
#[serde(untagged)]
57+
enum StringOrVec {
58+
String(String),
59+
Vec(Vec<String>),
60+
}
61+
62+
match StringOrVec::deserialize(deserializer)? {
63+
StringOrVec::String(s) => Ok(s.split(',').map(|item| item.trim().to_string()).collect()),
64+
StringOrVec::Vec(v) => Ok(v),
65+
}
66+
}
67+
5068
#[derive(Debug, Deserialize, Clone)]
5169
#[serde(default)]
5270
pub struct GrpcConfig {
5371
pub rqd_port: u16,
5472
pub rqd_interface: Option<String>,
73+
#[serde(deserialize_with = "string_or_vec")]
5574
pub cuebot_endpoints: Vec<String>,
5675
#[serde(with = "humantime_serde")]
5776
pub connection_expires_after: Duration,
@@ -68,7 +87,7 @@ impl Default for GrpcConfig {
6887
GrpcConfig {
6988
rqd_port: 8444,
7089
rqd_interface: None,
71-
cuebot_endpoints: vec!["localhost:4343".to_string()],
90+
cuebot_endpoints: vec!["localhost:8443".to_string()],
7291
connection_expires_after: Duration::from_secs(3600), // 1h. from_hour is experimental
7392
backoff_delay_min: Duration::from_millis(10),
7493
backoff_delay_max: Duration::from_secs(60),
@@ -250,7 +269,11 @@ impl Config {
250269

251270
let config = ConfigBase::builder()
252271
.add_source(File::with_name(&config_file).required(required))
253-
.add_source(Environment::with_prefix("OPENRQD").separator("_"))
272+
.add_source(
273+
Environment::with_prefix("OPENRQD")
274+
.separator("__")
275+
.list_separator(","),
276+
)
254277
.build()
255278
.map_err(|err| {
256279
RqdConfigError::LoadConfigError(format!(

rust/crates/rqd/src/system/linux.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ impl LinuxSystem {
339339
let addr = addrs_iter
340340
.next()
341341
.ok_or_else(|| miette::miette!("Failed to find IP for {}", hostname))?;
342-
Ok(addr.to_string())
342+
Ok(addr.ip().to_string())
343343
} else {
344344
Ok(hostname)
345345
}
@@ -594,7 +594,6 @@ impl LinuxSystem {
594594
Ok(())
595595
}
596596

597-
598597
// Read stats from /proc/{pid}/stat file and return session_id
599598
// NSsid might be is missing from /proc/{pid}/status
600599
// In this case we fallback if not found and and then use stat instead
@@ -615,12 +614,12 @@ impl LinuxSystem {
615614

616615
match end {
617616
Some(end) => {
618-
let fields: Vec<&str> = stat[end+2..].split_whitespace().collect();
619-
return fields[3].parse::<u32>().ok()
620-
},
617+
let fields: Vec<&str> = stat[end + 2..].split_whitespace().collect();
618+
return fields[3].parse::<u32>().ok();
619+
}
621620
None => {
622621
let fields: Vec<&str> = stat.split_whitespace().collect();
623-
return fields[5].parse::<u32>().ok()
622+
return fields[5].parse::<u32>().ok();
624623
}
625624
}
626625
}

0 commit comments

Comments
 (0)