Skip to content

Commit

Permalink
merge: #2723
Browse files Browse the repository at this point in the history
2723: feat(si): Recreate SDF or Web containers when port mappings change r=stack72 a=stack72

Closes: #2700

If you want to  change the port map for SDF or Web, then you'd currently
need to stop and delete the containers manually then re-run start

With this PR we can now do the following:

```
si --sdf-port 5157 start
```

This caused the Launcher to act as follows:

```
Container Port Mappings have changed for local-web-1 so recreating
Stopping container /local-web-1
Deleting container: local-web-1 (4d15095f701d8f2872a4e5a838f1187d1e0b980297bd23d15c21bc966eb41188)
Starting systeminit/web:stable as local-web-1
All system components running... System Initiative is alive!

You can now use the `si launch` command to open the System Initiative web portal:
```


Co-authored-by: stack72 <[email protected]>
  • Loading branch information
si-bors-ng[bot] and stack72 authored Sep 6, 2023
2 parents 3fd0994 + e80885a commit d88b9e6
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 12 deletions.
96 changes: 84 additions & 12 deletions lib/si-cli/src/cmd/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,53 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
let mut needs_recreated = false;
if let Some(ports) = existing.ports {
if !ports.is_empty() {
let port = ports.first().unwrap().clone();
let public_port = port.public_port.unwrap_or(0);
let ip = port.ip.clone().unwrap_or("".to_string());

if public_port as u32 != app.sdf_port() || ip != app.sdf_host() {
needs_recreated = true;
}
}
} else {
// No ports suggest that the container isn't in a started state
needs_recreated = true
}

// it means we have an existing container
// If it's running, we have nothing to do here
if existing.state.as_ref().unwrap() == "running" {
if existing.state.as_ref().unwrap() == "running" && !needs_recreated {
continue;
}

println!("Starting existing {0}", container_name.clone());
app.container_engine()
.start_container(existing.id.as_ref().unwrap().to_string())
.await?;
continue;
if needs_recreated {
println!(
"Container Port Mappings have changed for {0} so recreating",
container_name.clone()
);

if existing.state.as_ref().unwrap() == "running" {
app.container_engine()
.stop_container(existing.id.as_ref().unwrap().to_string())
.await?;
}

app.container_engine()
.delete_container(
existing.id.as_ref().unwrap().to_string(),
container_name.clone(),
)
.await?;
} else {
println!("Starting existing {0}", container_name.clone());
app.container_engine()
.start_container(existing.id.as_ref().unwrap().to_string())
.await?;
continue;
}
}

if is_preview {
Expand Down Expand Up @@ -354,17 +390,53 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
let mut needs_recreated = false;
if let Some(ports) = existing.ports {
if !ports.is_empty() {
let port = ports.first().unwrap().clone();
let public_port = port.public_port.unwrap_or(0);
let ip = port.ip.clone().unwrap_or("".to_string());

if public_port as u32 != app.web_port() || ip != app.web_host() {
needs_recreated = true;
}
}
} else {
// No ports suggest that the container isn't in a started state
needs_recreated = true
}

// it means we have an existing container
// If it's running, we have nothing to do here
if existing.state.as_ref().unwrap() == "running" {
if existing.state.as_ref().unwrap() == "running" && !needs_recreated {
continue;
}

println!("Starting existing {0}", container_name.clone());
app.container_engine()
.start_container(existing.id.as_ref().unwrap().to_string())
.await?;
continue;
if needs_recreated {
println!(
"Container Port Mappings have changed for {0} so recreating",
container_name.clone()
);

if existing.state.as_ref().unwrap() == "running" {
app.container_engine()
.stop_container(existing.id.as_ref().unwrap().to_string())
.await?;
}

app.container_engine()
.delete_container(
existing.id.as_ref().unwrap().to_string(),
container_name.clone(),
)
.await?;
} else {
println!("Starting existing {0}", container_name.clone());
app.container_engine()
.start_container(existing.id.as_ref().unwrap().to_string())
.await?;
continue;
}
}

if is_preview {
Expand Down
44 changes: 44 additions & 0 deletions lib/si-cli/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,25 @@ pub struct ContainerReleaseInfo {
pub version: String,
}

#[derive(Debug)]
pub struct SiContainerSummary {
pub created: Option<i64>,
pub id: Option<String>,
pub image: Option<String>,
pub labels: Option<HashMap<String, String>>,
pub status: Option<String>,
pub state: Option<String>,
pub ports: Option<Vec<SiPort>>,
}

#[derive(Debug)]
pub struct SiPort {
pub ip: Option<String>,
pub private_port: u16,
pub public_port: Option<u16>,
}

#[derive(Debug)]
pub struct SiImageSummary {
pub containers: isize,
pub created: isize,
Expand All @@ -94,13 +104,40 @@ impl From<docker_api::models::ImageSummary> for SiImageSummary {

impl From<docker_api::models::ContainerSummary> for SiContainerSummary {
fn from(container: docker_api::models::ContainerSummary) -> SiContainerSummary {
let mut mapped_ports = Vec::new();
if let Some(ports) = container.ports {
for port in ports {
mapped_ports.push(SiPort::from(port))
}
}
SiContainerSummary {
created: container.created,
id: container.id,
image: container.image,
labels: container.labels,
status: container.status,
state: container.state,
ports: Some(mapped_ports),
}
}
}

impl From<docker_api::models::Port> for SiPort {
fn from(port: docker_api::models::Port) -> SiPort {
SiPort {
ip: port.ip,
private_port: port.private_port,
public_port: port.public_port,
}
}
}

impl From<podman_api::models::PortMapping> for SiPort {
fn from(port: podman_api::models::PortMapping) -> SiPort {
SiPort {
ip: port.host_ip,
private_port: port.container_port.unwrap_or(0),
public_port: port.host_port,
}
}
}
Expand Down Expand Up @@ -144,13 +181,20 @@ impl From<podman_api::models::LibpodImageSummary> for SiImageSummary {

impl From<podman_api::models::ListContainer> for SiContainerSummary {
fn from(container: podman_api::models::ListContainer) -> SiContainerSummary {
let mut mapped_ports = Vec::new();
if let Some(ports) = container.ports {
for port in ports {
mapped_ports.push(SiPort::from(port))
}
}
SiContainerSummary {
created: container.created.map(|created| created.timestamp()),
id: container.id,
image: container.image,
labels: container.labels,
status: container.status,
state: container.state,
ports: Some(mapped_ports),
}
}
}

0 comments on commit d88b9e6

Please sign in to comment.