opencode_cloud_core/docker/
mod.rs1mod client;
16pub mod container;
17mod dockerfile;
18mod error;
19pub mod exec;
20mod health;
21pub mod image;
22pub mod progress;
23pub mod state;
24pub mod update;
25pub mod users;
26mod version;
27pub mod volume;
28
29pub use client::DockerClient;
31pub use error::DockerError;
32pub use progress::ProgressReporter;
33
34pub use health::{
36 ExtendedHealthResponse, HealthError, HealthResponse, check_health, check_health_extended,
37};
38
39pub use dockerfile::{DOCKERFILE, IMAGE_NAME_DOCKERHUB, IMAGE_NAME_GHCR, IMAGE_TAG_DEFAULT};
41
42pub use image::{build_image, image_exists, pull_image};
44
45pub use update::{UpdateResult, has_previous_image, rollback_image, update_image};
47
48pub use version::{VERSION_LABEL, get_cli_version, get_image_version, versions_compatible};
50
51pub use exec::{exec_command, exec_command_exit_code, exec_command_with_stdin};
53
54pub use users::{
56 UserInfo, create_user, delete_user, list_users, lock_user, set_user_password, unlock_user,
57 user_exists,
58};
59
60pub use volume::{
62 MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION, VOLUME_CONFIG, VOLUME_NAMES, VOLUME_PROJECTS,
63 VOLUME_SESSION, ensure_volumes_exist, remove_all_volumes, remove_volume, volume_exists,
64};
65
66pub use container::{
68 CONTAINER_NAME, OPENCODE_WEB_PORT, container_exists, container_is_running, container_state,
69 create_container, remove_container, start_container, stop_container,
70};
71
72pub use state::{ImageState, clear_state, get_state_path, load_state, save_state};
74
75pub async fn setup_and_start(
88 client: &DockerClient,
89 opencode_web_port: Option<u16>,
90 env_vars: Option<Vec<String>>,
91 bind_address: Option<&str>,
92 cockpit_port: Option<u16>,
93 cockpit_enabled: Option<bool>,
94) -> Result<String, DockerError> {
95 volume::ensure_volumes_exist(client).await?;
97
98 let container_id = if container::container_exists(client, container::CONTAINER_NAME).await? {
100 let info = client
102 .inner()
103 .inspect_container(container::CONTAINER_NAME, None)
104 .await
105 .map_err(|e| {
106 DockerError::Container(format!("Failed to inspect existing container: {e}"))
107 })?;
108 info.id
109 .unwrap_or_else(|| container::CONTAINER_NAME.to_string())
110 } else {
111 container::create_container(
113 client,
114 None,
115 None,
116 opencode_web_port,
117 env_vars,
118 bind_address,
119 cockpit_port,
120 cockpit_enabled,
121 )
122 .await?
123 };
124
125 if !container::container_is_running(client, container::CONTAINER_NAME).await? {
127 container::start_container(client, container::CONTAINER_NAME).await?;
128 }
129
130 Ok(container_id)
131}
132
133pub const DEFAULT_STOP_TIMEOUT_SECS: i64 = 30;
135
136pub async fn stop_service(
143 client: &DockerClient,
144 remove: bool,
145 timeout_secs: Option<i64>,
146) -> Result<(), DockerError> {
147 let name = container::CONTAINER_NAME;
148 let timeout = timeout_secs.unwrap_or(DEFAULT_STOP_TIMEOUT_SECS);
149
150 if !container::container_exists(client, name).await? {
152 return Err(DockerError::Container(format!(
153 "Container '{name}' does not exist"
154 )));
155 }
156
157 if container::container_is_running(client, name).await? {
159 container::stop_container(client, name, Some(timeout)).await?;
160 }
161
162 if remove {
164 container::remove_container(client, name, false).await?;
165 }
166
167 Ok(())
168}