Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Ubuntu 18.04 to installer #1231

Merged
merged 7 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
25 changes: 14 additions & 11 deletions .github/workflows/kani.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-10.15, ubuntu-20.04]
os: [macos-10.15, ubuntu-18.04]
include:
- os: macos-10.15
artifact: kani-latest-x86_64-apple-darwin.tar.gz
- os: ubuntu-20.04
- os: ubuntu-18.04
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to get rid of ubuntu-20? Or should we have it as a third option

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"get rid of" in what sense? Are you saying not building the regressions (currently 18, 20, and mac) there anymore?

I would sort of endorse that, in that I think we don't need the regressions running on two linux platforms... but what we DO need is "install/smoke testing" running on multiple linux platforms... which is sort of what this is simulating, but it's not good enough yet.

I spent an hour with a whiteboard yesterday trying to sketch out what I thought we'd ideally want to work towards in terms of CI flow and found it a bit frustratingly complicated. I might write up a doc/proposal soon...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielsn Note that this is for building the release bundle, and we're building a single bundle for both Ubuntu 18.04 and Ubuntu 20.04.

artifact: kani-latest-x86_64-unknown-linux-gnu.tar.gz
steps:
- name: Checkout Kani
Expand All @@ -96,26 +96,29 @@ jobs:
cargo package -p kani-verifier

- name: Build container test
if: ${{ matrix.os == 'ubuntu-20.04' }}
if: ${{ matrix.os == 'ubuntu-18.04' }}
run: |
docker build -t kani-latest -f scripts/ci/Dockerfile.release-bundle-test .
docker build -t kani-20-04 -f scripts/ci/Dockerfile.bundle-test-20-04 .
docker build -t kani-18-04 -f scripts/ci/Dockerfile.bundle-test-18-04 .

- name: Run installed tests
if: ${{ matrix.os == 'ubuntu-20.04' }}
if: ${{ matrix.os == 'ubuntu-18.04' }}
run: |
docker run kani-latest cargo kani --version
docker run -w /tmp/kani/tests/cargo-kani/simple-lib kani-latest cargo kani
docker run -w /tmp/kani/tests/cargo-kani/simple-visualize kani-latest cargo kani
docker run -w /tmp/kani/tests/cargo-kani/build-rs-works kani-latest cargo kani
docker run kani-latest cargo-kani setup --use-local-bundle ./kani-latest-x86_64-unknown-linux-gnu.tar.gz
for tag in kani-20-04 kani-18-04; do
docker run $tag cargo kani --version
docker run -w /tmp/kani/tests/cargo-kani/simple-lib $tag cargo kani
docker run -w /tmp/kani/tests/cargo-kani/simple-visualize $tag cargo kani
docker run -w /tmp/kani/tests/cargo-kani/build-rs-works $tag cargo kani
docker run $tag cargo-kani setup --use-local-bundle ./${{ matrix.artifact }}
done

# We can't run macos in a container, so we can only test locally.
# Hopefully any dependency issues won't be unique to macos.
- name: Local install test
if: ${{ matrix.os == 'macos-10.15' }}
run: |
cargo install --path ./target/package/kani-verifier-*[^e]
cargo-kani setup --use-local-bundle ./kani-latest-x86_64-apple-darwin.tar.gz
cargo-kani setup --use-local-bundle ./${{ matrix.artifact }}
(cd tests/cargo-kani/simple-lib && cargo kani)
(cd tests/cargo-kani/simple-visualize && cargo kani)
(cd tests/cargo-kani/build-rs-works && cargo kani)
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ version = "0.2.0"
dependencies = [
"anyhow",
"home",
"os_info",
]

[[package]]
Expand Down Expand Up @@ -637,6 +638,16 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"

[[package]]
name = "os_info"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62"
dependencies = [
"log",
"winapi",
]

[[package]]
name = "parking_lot"
version = "0.12.0"
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ include = ["/src", "/build.rs", "/rust-toolchain.toml", "/LICENSE-*", "/README.m
[dependencies]
anyhow = "1"
home = "0.5"
os_info = { version = "3", default-features = false }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo uses os_info so probably a good choice :) https://crates.io/crates/os_info/reverse_dependencies


[[bin]]
name = "kani"
Expand Down
20 changes: 20 additions & 0 deletions scripts/ci/Dockerfile.bundle-test-18-04
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright Kani Contributors
# SPDX-License-Identifier: Apache-2.0 OR MIT

# Note: this file is intended only for testing the kani release bundle

FROM ubuntu:18.04
ENV DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true
RUN apt-get update && \
apt-get install -y python3 python3-pip curl ctags && \
curl -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

WORKDIR /tmp/kani
COPY ./tests ./tests
COPY ./kani-latest-x86_64-unknown-linux-gnu.tar.gz ./
# Very awkward glob (not regex!) to get `kani-verifier-*` and not `kani-verifier-*.crate`
COPY ./target/package/kani-verifier-*[^e] ./kani-verifier
RUN cargo install --path ./kani-verifier
RUN cargo-kani setup --use-local-bundle ./kani-latest-x86_64-unknown-linux-gnu.tar.gz
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#![warn(clippy::all, clippy::cargo)]

mod cmd;
mod os_hacks;
mod setup;

use std::env;
Expand Down
44 changes: 44 additions & 0 deletions src/os_hacks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! In order to avoid introducing a large amount of OS-specific workarounds into the main
//! "flow" of code in setup.rs, this module contains all functions that implement os-specific
//! workarounds.

use std::ffi::OsString;
use std::path::Path;
use std::process::Command;

use anyhow::Result;

use crate::cmd::AutoRun;

/// See [`crate::setup::setup_python_deps`]
pub fn setup_python_deps_on_ubuntu_18_04(pyroot: &Path, pkg_versions: &[&str]) -> Result<()> {
println!("Applying a workaround for 18.04...");
// https://github.com/pypa/pip/issues/3826
// Ubuntu 18.04 has a patched-to-be-broken version of pip that just straight-up makes `--target` not work.
// Worse still, there is no apparent way to replicate the correct behavior cleanly.

// This is a really awful hack to simulate getting the same result. I can find no other solution.
// Example failed approach: `--system --target pyroot` fails to create a `pyroot/bin` with binaries.

// Step 1: use `--system --prefix pyroot`. This disables the broken behavior, and creates `bin` but...
Command::new("python3")
.args(&["-m", "pip", "install", "--system", "--prefix"])
.arg(&pyroot)
.args(pkg_versions)
.run()?;

// Step 2: move `pyroot/lib/python3.6/site-packages/*` up to `pyroot`
// This seems to successfully replicate the behavior of `--target`
// "mv" is not idempotent however so we need to do "cp -r"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're doing cp instead of mv, should we:

  1. Rename the variable
  2. Delete the source directory after copying it
    ?
    I'm a bit unclear on the issue with mv.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mv makes the setup procedure non-idempotent because it fails if the directory already exists (from a previous install).

I can rename the variable and delete the extra directory, that seems reasonable.

let mut mv_cmd = OsString::new();
mv_cmd.push("cp -r ");
mv_cmd.push(pyroot.as_os_str());
mv_cmd.push("/lib/python*/site-packages/* ");
mv_cmd.push(pyroot.as_os_str());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a risk that the target directory is not writeable (or requires sudo)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, pyroot here is ~/.kani/kani-VERSION/pyroot and we created it.

Command::new("bash").arg("-c").arg(mv_cmd).run()?;

Ok(())
}
18 changes: 15 additions & 3 deletions src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub fn appears_setup() -> bool {
/// Sets up Kani by unpacking/installing to `~/.kani/kani-VERSION`
pub fn setup(use_local_bundle: Option<OsString>) -> Result<()> {
let kani_dir = kani_dir();
let os = os_info::get();

println!("[0/6] Running Kani first-time setup...");

Expand All @@ -43,7 +44,7 @@ pub fn setup(use_local_bundle: Option<OsString>) -> Result<()> {

let toolchain_version = setup_rust_toolchain(&kani_dir)?;

setup_python_deps(&kani_dir)?;
setup_python_deps(&kani_dir, &os)?;

setup_build_kani_prelude(&kani_dir, toolchain_version)?;

Expand Down Expand Up @@ -103,15 +104,26 @@ fn setup_rust_toolchain(kani_dir: &Path) -> Result<String> {
}

/// Install into the pyroot the python dependencies we need
fn setup_python_deps(kani_dir: &Path) -> Result<()> {
fn setup_python_deps(kani_dir: &Path, os: &os_info::Info) -> Result<()> {
println!("[4/6] Installing Kani python dependencies...");
let pyroot = kani_dir.join("pyroot");

// TODO: this is a repetition of versions from kani/scripts/setup/$OS/install_deps.sh
let pkg_versions = &["cbmc-viewer==3.2", "colorama==0.4.3"];

if os.os_type() == os_info::Type::Ubuntu
&& *os.version() == os_info::Version::Semantic(18, 4, 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a risk there will be an 18.4.1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is not a risk of that because I think it's already running on "18.4.4" and not picking that up. I believe what's happening is it's parsing "18.04" as if it were a version number.

I agree this is seems fragile but this unit test seems to confirm this is the expected behavior: https://github.com/stanislav-tkach/os_info/blob/master/os_info/src/linux/lsb_release.rs#L317-L318

{
crate::os_hacks::setup_python_deps_on_ubuntu_18_04(&pyroot, pkg_versions)?;
return Ok(());
}

Command::new("python3")
.args(&["-m", "pip", "install", "cbmc-viewer==3.2", "colorama==0.4.3", "--target"])
.args(&["-m", "pip", "install", "--target"])
.arg(&pyroot)
.args(pkg_versions)
.run()?;

Ok(())
}

Expand Down