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

Rewrite package install strategy. #1093

Merged
merged 1 commit into from Aug 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
380 changes: 191 additions & 189 deletions components/common/src/command/package/install.rs

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions components/common/src/error.rs
Expand Up @@ -27,6 +27,7 @@ pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
ArtifactIdentMismatch((String, String, String)),
CantUploadGossipToml,
CryptoKeyError(String),
GossipFileRelativePath(String),
Expand All @@ -46,6 +47,12 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
Error::ArtifactIdentMismatch((ref a, ref ai, ref i)) => {
format!("Artifact ident {} for `{}' does not match expected ident {}",
Copy link
Contributor

Choose a reason for hiding this comment

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

very nice!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

gif-keyboard-14819133391177303892

ai,
a,
i)
}
Error::CantUploadGossipToml => {
format!("Can't upload gossip.toml, it's a reserved file name")
}
Expand All @@ -72,6 +79,9 @@ impl fmt::Display for Error {
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::ArtifactIdentMismatch((_, _, _)) => {
"Artifact ident does not match expected ident"
}
Error::CantUploadGossipToml => "Can't upload gossip.toml, it's a reserved filename",
Error::CryptoKeyError(_) => "Missing or invalid key",
Error::GossipFileRelativePath(_) => {
Expand Down
14 changes: 7 additions & 7 deletions components/hab/src/command/pkg.rs
Expand Up @@ -219,13 +219,13 @@ pub mod export {
println!("Searching for {} in remote {}",
&format_ident.to_string(),
&default_depot_url());
try!(install::from_url(&default_depot_url(),
format_ident,
PRODUCT,
VERSION,
Path::new(FS_ROOT_PATH),
&cache_artifact_path(None),
&default_cache_key_path(None)));
try!(install::start(&default_depot_url(),
&format_ident.to_string(),
PRODUCT,
VERSION,
Path::new(FS_ROOT_PATH),
&cache_artifact_path(None),
&default_cache_key_path(None)));
}
}
let pkg_arg = OsString::from(&ident.to_string());
Expand Down
14 changes: 7 additions & 7 deletions components/hab/src/exec.rs
Expand Up @@ -98,13 +98,13 @@ pub fn command_from_pkg(command: &str,
println!("{}",
Cyan.bold()
.paint(format!("∵ Package for {} not found, installing", &ident)));
try!(common::command::package::install::from_url(&default_depot_url(),
ident,
PRODUCT,
VERSION,
fs_root_path,
&cache_artifact_path(None),
cache_key_path));
try!(common::command::package::install::start(&default_depot_url(),
&ident.to_string(),
PRODUCT,
VERSION,
fs_root_path,
&cache_artifact_path(None),
cache_key_path));
command_from_pkg(&command, &ident, &cache_key_path, retry + 1)
}
Err(e) => return Err(Error::from(e)),
Expand Down
2 changes: 1 addition & 1 deletion components/hab/src/gossip.rs
Expand Up @@ -84,7 +84,7 @@ pub mod hab_gossip {
use common::gossip_file::GossipFile;
use common::wire_message::WireMessage;
use hcore::crypto::SymKey;
use rustc_serialize::{json, Encodable};
use rustc_serialize::json;
use utp::UtpSocket;
use uuid::Uuid;

Expand Down
93 changes: 51 additions & 42 deletions components/sup/src/command/start.rs
Expand Up @@ -60,15 +60,14 @@ use std::env;
use std::path::Path;

use ansi_term::Colour::Yellow;
use common::command::ProgressBar;
use common::command::package::install;
use depot_client::Client;
use hcore::crypto::default_cache_key_path;
use hcore::fs::{cache_artifact_path, FS_ROOT_PATH};
use hcore::package::PackageIdent;

use {PRODUCT, VERSION};
use error::{Error, Result};
use error::Result;
use config::{Config, UpdateStrategy};
use package::Package;
use topology::{self, Topology};
Expand All @@ -85,61 +84,71 @@ static LOGKEY: &'static str = "CS";
/// * Fails if an unknown topology was specified on the command line
pub fn package(config: &Config) -> Result<()> {
match Package::load(config.package(), None) {
Ok(package) => {
Ok(mut package) => {
let update_strategy = config.update_strategy();
match update_strategy {
UpdateStrategy::None => {}
_ => {
if let &Some(ref url) = config.url() {
outputln!("Checking remote for newer versions...");
// It is important to pass `config.package()` to `show_package()` instead of the
// package identifier of the loaded package. This will ensure that if the operator
// starts a package while specifying a version number, they will only automaticaly
// receive release updates for the started package.
//
// If the operator does not specify a version number they will automatically receive
// updates for any releases, regardless of version number, for the started package.
let depot_client = try!(Client::new(url, PRODUCT, VERSION, None));
let latest_pkg_data =
try!(depot_client.show_package((*config.package()).clone()));
let latest_ident: PackageIdent = latest_pkg_data.get_ident().clone().into();
if &latest_ident > package.ident() {
outputln!("Downloading latest version from remote: {}", latest_ident);
let mut progress = ProgressBar::default();
let archive = try!(depot_client.fetch_package(latest_ident,
&cache_artifact_path(None),
Some(&mut progress)));
try!(archive.verify(&default_cache_key_path(None)));
try!(archive.unpack(None));
} else {
outputln!("Already running latest.");
};
}
let url = config.url();
outputln!("Checking Depot for newer versions...");
// It is important to pass `config.package()` to `show_package()` instead
// of the package identifier of the loaded package. This will ensure that
// if the operator starts a package while specifying a version number, they
// will only automaticaly receive release updates for the started package.
//
// If the operator does not specify a version number they will
// automatically receive updates for any releases, regardless of version
// number, for the started package.
let depot_client = try!(Client::new(url, PRODUCT, VERSION, None));
let latest_pkg_data =
try!(depot_client.show_package((*config.package()).clone()));
let latest_ident: PackageIdent = latest_pkg_data.get_ident().clone().into();
if &latest_ident > package.ident() {
outputln!("Downloading latest version from Depot: {}", latest_ident);
let new_pkg_data = try!(install::start(url,
&latest_ident.to_string(),
PRODUCT,
VERSION,
Path::new(FS_ROOT_PATH),
&cache_artifact_path(None),
&default_cache_key_path(None)));
package = try!(Package::load(&new_pkg_data, None));
} else {
outputln!("Already running latest.");
};
}
}
start_package(package, config)
}
Err(_) => {
outputln!("{} is not installed",
Yellow.bold().paint(config.package().to_string()));
match *config.url() {
Some(ref url) => {
let url = config.url();
let new_pkg_data = match config.local_artifact() {
Some(artifact) => {
try!(install::start(url,
&artifact,
PRODUCT,
VERSION,
Path::new(FS_ROOT_PATH),
&cache_artifact_path(None),
&default_cache_key_path(None)))
}
None => {
outputln!("Searching for {} in remote {}",
Yellow.bold().paint(config.package().to_string()),
url);
let new_pkg_data = try!(install::from_url(url,
config.package(),
PRODUCT,
VERSION,
Path::new(FS_ROOT_PATH),
&cache_artifact_path(None),
&default_cache_key_path(None)));
let package = try!(Package::load(&new_pkg_data.get_ident().clone().into(),
None));
start_package(package, config)
try!(install::start(url,
&config.package().to_string(),
PRODUCT,
VERSION,
Path::new(FS_ROOT_PATH),
&cache_artifact_path(None),
&default_cache_key_path(None)))
}
None => Err(sup_error!(Error::PackageNotFound(config.package().clone()))),
}
};
let package = try!(Package::load(&new_pkg_data, None));
start_package(package, config)
}
}
}
Expand Down
18 changes: 14 additions & 4 deletions components/sup/src/config.rs
Expand Up @@ -85,7 +85,8 @@ impl Default for Command {
pub struct Config {
command: Command,
package: PackageIdent,
url: Option<String>,
local_artifact: Option<String>,
url: String,
topology: Topology,
group: String,
path: String,
Expand Down Expand Up @@ -261,12 +262,12 @@ impl Config {

/// Set the url
pub fn set_url(&mut self, url: String) -> &mut Config {
self.url = Some(url);
self.url = url;
self
}

/// Return the url
pub fn url(&self) -> &Option<String> {
pub fn url(&self) -> &str {
&self.url
}

Expand Down Expand Up @@ -382,6 +383,15 @@ impl Config {
&self.package
}

pub fn set_local_artifact(&mut self, artifact: String) -> &mut Config {
self.local_artifact = Some(artifact);
self
}

pub fn local_artifact(&self) -> Option<&str> {
self.local_artifact.as_ref().map(String::as_ref)
}

pub fn set_organization(&mut self, org: String) -> &mut Config {
self.organization = Some(org);
self
Expand Down Expand Up @@ -439,7 +449,7 @@ mod tests {
fn url() {
let mut c = Config::new();
c.set_url(String::from("http://foolio.com"));
assert_eq!(c.url().as_ref().unwrap(), "http://foolio.com");
assert_eq!(c.url(), "http://foolio.com");
}

#[test]
Expand Down
22 changes: 15 additions & 7 deletions components/sup/src/main.rs
Expand Up @@ -24,6 +24,7 @@ extern crate libc;
#[macro_use]
extern crate clap;

use std::path::Path;
use std::process;
use std::result;
use std::str::FromStr;
Expand All @@ -34,7 +35,7 @@ use hcore::env as henv;
use hcore::fs;
use hcore::crypto::{default_cache_key_path, SymKey};
use hcore::crypto::init as crypto_init;
use hcore::package::PackageIdent;
use hcore::package::{PackageArchive, PackageIdent};
use hcore::url::{DEFAULT_DEPOT_URL, DEPOT_URL_ENVVAR};

use sup::config::{Command, Config, UpdateStrategy};
Expand Down Expand Up @@ -74,9 +75,15 @@ fn config_from_args(subcommand: &str, sub_args: &ArgMatches) -> Result<Config> {
if let Some(ref archive) = sub_args.value_of("archive") {
config.set_archive(archive.to_string());
}
if let Some(ref package) = sub_args.value_of("package") {
let ident = try!(PackageIdent::from_str(package));
config.set_package(ident);
if let Some(ref ident_or_artifact) = sub_args.value_of("pkg_ident_or_artifact") {
if Path::new(ident_or_artifact).is_file() {
let ident = try!(PackageArchive::new(Path::new(ident_or_artifact)).ident());
config.set_package(ident);
config.set_local_artifact(ident_or_artifact.to_string());
} else {
let ident = try!(PackageIdent::from_str(ident_or_artifact));
config.set_package(ident);
}
}
if let Some(key) = sub_args.value_of("key") {
config.set_key(key.to_string());
Expand Down Expand Up @@ -255,12 +262,13 @@ fn main() {
};

let sub_start = SubCommand::with_name("start")
.about("Start a Habitat-supervised service from a package")
.about("Start a Habitat-supervised service from a package or artifact")
.aliases(&["st", "sta", "star"])
.arg(Arg::with_name("package")
.arg(Arg::with_name("pkg_ident_or_artifact")
.index(1)
.required(true)
.help("Name of package to start"))
.help("A Habitat package identifier (ex: acme/redis) or a filepath to a Habitat \
Artifact (ex: /home/acme-redis-3.0.7-21120102031201-x86_64-linux.hart)"))
.arg(arg_url())
.arg(arg_group())
.arg(arg_org())
Expand Down
4 changes: 1 addition & 3 deletions components/sup/src/topology/mod.rs
Expand Up @@ -148,9 +148,7 @@ impl<'a> Worker<'a> {
UpdateStrategy::None => {}
_ => {
let pkg_lock_2 = pkg_lock.clone();
if let &Some(ref url) = config.url() {
pkg_updater = Some(package::PackageUpdater::start(url, pkg_lock_2));
}
pkg_updater = Some(package::PackageUpdater::start(config.url(), pkg_lock_2));
}
}

Expand Down
1 change: 0 additions & 1 deletion components/sup/tests/util/command.rs
Expand Up @@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::prelude::*;
use std::io;
use std::process::{Command, Child, Stdio, ExitStatus};
use std::fmt;
Expand Down