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

honor pkg_svc_user/pkg_svc_group #1012

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions components/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub enum Error {
/// When an error occurs parsing an integer.
ParseIntError(num::ParseIntError),
/// Occurs when setting ownership or permissions on a file or directory fails.
PermissionFailed,
PermissionFailed(String),
/// When an error occurs parsing or compiling a regular expression.
RegexParse(regex::Error),
/// When an error occurs converting a `String` from a UTF-8 byte vector.
Expand Down Expand Up @@ -141,7 +141,7 @@ impl fmt::Display for Error {
}
}
Error::ParseIntError(ref e) => format!("{}", e),
Error::PermissionFailed => format!("Failed to set permissions"),
Error::PermissionFailed(ref e) => format!("{}", e),
Error::RegexParse(ref e) => format!("{}", e),
Error::StringFromUtf8Error(ref e) => format!("{}", e),
Error::UnameFailed(ref e) => format!("{}", e),
Expand Down Expand Up @@ -187,7 +187,7 @@ impl error::Error for Error {
Error::NoOutboundAddr => "Failed to discover the outbound IP address",
Error::PackageNotFound(_) => "Cannot find a package",
Error::ParseIntError(_) => "Failed to parse an integer from a string!",
Error::PermissionFailed => "Failed to set permissions",
Error::PermissionFailed(_) => "Failed to set permissions",
Error::RegexParse(_) => "Failed to parse a regular expression",
Error::StringFromUtf8Error(_) => "Failed to convert a string from a Vec<u8> as UTF-8",
Error::UnameFailed(_) => "uname failed",
Expand Down
20 changes: 20 additions & 0 deletions components/core/src/package/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,26 @@ impl PackageInstall {
fs::svc_var_path(&self.ident.name)
}

/// Returns the user that the package is specified to run as
/// or None if the package doesn't contain a SVC_USER Metafile
pub fn svc_user(&self) -> Result<Option<String>> {
match self.read_metafile(MetaFile::SvcUser) {
Ok(body) => Ok(Some(body)),
Err(Error::MetaFileNotFound(MetaFile::SvcUser)) => Ok(None),
Err(e) => Err(e),
}
}

/// Returns the group that the package is specified to run as
/// or None if the package doesn't contain a SVC_GROUP Metafile
pub fn svc_group(&self) -> Result<Option<String>> {
match self.read_metafile(MetaFile::SvcGroup) {
Ok(body) => Ok(Some(body)),
Err(Error::MetaFileNotFound(MetaFile::SvcGroup)) => Ok(None),
Err(e) => Err(e),
}
}

/// Read the contents of a given metafile.
///
/// # Failures
Expand Down
4 changes: 4 additions & 0 deletions components/core/src/package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub enum MetaFile {
LdFlags,
Manifest,
Path,
SvcUser,
SvcGroup,
}

impl fmt::Display for MetaFile {
Expand All @@ -49,6 +51,8 @@ impl fmt::Display for MetaFile {
MetaFile::LdFlags => "LDFLAGS",
MetaFile::Manifest => "MANIFEST",
MetaFile::Path => "PATH",
MetaFile::SvcUser => "SVC_USER",
MetaFile::SvcGroup => "SVC_GROUP",
};
write!(f, "{}", id)
}
Expand Down
19 changes: 17 additions & 2 deletions components/core/src/util/perm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,41 @@ use std::path::Path;
use error::{Error, Result};

pub fn set_owner<T: AsRef<Path>, X: AsRef<str>>(path: T, owner: X) -> Result<()> {
debug!("Attempting to set owner of {:?} to {:?}",
&path.as_ref(),
&owner.as_ref());
let output = try!(Command::new("chown")
.arg(owner.as_ref())
.arg(path.as_ref())
.output());
match output.status.success() {
true => Ok(()),
false => Err(Error::PermissionFailed),
false => {
Err(Error::PermissionFailed(format!("Can't change owner of {:?} to {:?}",
&path.as_ref(),
&owner.as_ref())))
}
}
}

// When Rust stabilizes this interface, we can move to the cross
// platform abstraction. Until then, if we move to Windows or some
// other platform, this code will need to become platform specific.
pub fn set_permissions<T: AsRef<Path>, X: AsRef<str>>(path: T, perm: X) -> Result<()> {
debug!("Attempting to set permissions on {:?} to {:?}",
&path.as_ref(),
&perm.as_ref());
let output = try!(Command::new("chmod")
.arg(perm.as_ref())
.arg(path.as_ref())
.output());
match output.status.success() {
true => Ok(()),
false => Err(Error::PermissionFailed),
false => {
Err(Error::PermissionFailed(format!("Can't set permissions on {:?} to {:?}",
&path.as_ref(),
&perm.as_ref())))
}
}
}

1 change: 1 addition & 0 deletions components/depot/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions components/plan-build/bin/hab-plan-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1915,6 +1915,9 @@ _build_metadata() {
echo "${pkg_origin}/${pkg_name}/${pkg_version}/${pkg_release}" \
>> $pkg_prefix/IDENT

echo "$pkg_svc_user" > $pkg_prefix/SVC_USER
echo "$pkg_svc_group" > $pkg_prefix/SVC_GROUP

# Generate the blake2b hashes of all the files in the package. This
# is not in the resulting MANIFEST because MANIFEST is included!
pushd "$HAB_CACHE_SRC_PATH/$pkg_dirname" > /dev/null
Expand Down
1 change: 1 addition & 0 deletions components/sup/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions components/sup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ openssl = "*"
lazy_static = "*"
handlebars = "*"
wonder = "*"
users = "*"


[dependencies.habitat_core]
path = "../core"
Expand Down
3 changes: 3 additions & 0 deletions components/sup/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub enum Error {
DepotClient(depot_client::Error),
ExecCommandNotFound(String),
FileNotFound(String),
Permissions(String),
HabitatCommon(common::Error),
HabitatCore(hcore::Error),
HandlebarsTemplateFileError(handlebars::TemplateFileError),
Expand Down Expand Up @@ -152,6 +153,7 @@ impl fmt::Display for SupError {
Error::ExecCommandNotFound(ref c) => {
format!("`{}' was not found on the filesystem or in PATH", c)
}
Error::Permissions(ref err) => format!("{}", err),
Error::HabitatCommon(ref err) => format!("{}", err),
Error::HabitatCore(ref err) => format!("{}", err),
Error::HandlebarsTemplateFileError(ref err) => format!("{:?}", err),
Expand Down Expand Up @@ -239,6 +241,7 @@ impl error::Error for SupError {
match self.err {
Error::ActorError(_) => "A running actor responded with an error",
Error::ExecCommandNotFound(_) => "Exec command was not found on filesystem or in PATH",
Error::Permissions(_) => "File system permissions error",
Error::HandlebarsRenderError(ref err) => err.description(),
Error::HandlebarsTemplateFileError(ref err) => err.description(),
Error::HabitatCommon(ref err) => err.description(),
Expand Down
64 changes: 57 additions & 7 deletions components/sup/src/package/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ use std::process::{Command, Stdio};
use handlebars::Handlebars;

use error::{Error, Result};
use hcore::util;
use package::Package;
use service_config::{ServiceConfig, never_escape_fn};
use util::convert;
use util::users as hab_users;

static LOGKEY: &'static str = "PH";

pub const HOOK_PERMISSIONS: &'static str = "0755";

#[derive(Debug, Clone)]
pub enum HookType {
HealthCheck,
Expand All @@ -54,24 +58,33 @@ pub struct Hook {
pub htype: HookType,
pub template: PathBuf,
pub path: PathBuf,
pub user: String,
pub group: String,
}

impl Hook {
pub fn new(htype: HookType, template: PathBuf, path: PathBuf) -> Self {
pub fn new(htype: HookType,
template: PathBuf,
path: PathBuf,
user: String,
group: String)
-> Self {
Hook {
htype: htype,
template: template,
path: path,
user: user,
group: group,
}
}

pub fn run(&self, context: Option<&ServiceConfig>) -> Result<String> {
try!(self.compile(context));
let mut child = try!(Command::new(&self.path)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn());

let mut cmd = Command::new(&self.path);
try!(self.run_platform(&mut cmd));
let mut child = try!(cmd.spawn());

{
let mut c_stdout = match child.stdout {
Some(ref mut s) => s,
Expand Down Expand Up @@ -113,7 +126,37 @@ impl Hook {
}
}

#[cfg(any(target_os="linux", target_os="macos"))]
fn run_platform(&self, cmd: &mut Command) -> Result<()> {
use std::os::unix::process::CommandExt;
let uid = hab_users::user_name_to_uid(&self.user);
let gid = hab_users::group_name_to_gid(&self.group);
if let None = uid {
panic!("Can't determine uid");
}

if let None = gid {
panic!("Can't determine gid");
}

let uid = uid.unwrap();
let gid = gid.unwrap();
cmd.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.uid(uid)
.gid(gid);
Ok(())
}

#[cfg(target_os = "windows")]
fn run_platform(&self, cmd: &mut Command) -> Result<()> {
unimplemented!();
}

pub fn compile(&self, context: Option<&ServiceConfig>) -> Result<()> {
let runas = format!("{}:{}", &self.user, &self.group);

if let Some(ctx) = context {
debug!("Rendering hook {:?}", self);
let mut handlebars = Handlebars::new();
Expand All @@ -130,9 +173,13 @@ impl Hook {
.mode(0o770)
.open(&self.path));
try!(write!(&mut file, "{}", data));
try!(util::perm::set_owner(&self.path, &runas));
try!(util::perm::set_permissions(&self.path, HOOK_PERMISSIONS));
Ok(())
} else {
try!(fs::copy(&self.template, &self.path));
try!(util::perm::set_owner(&self.path, &runas));
try!(util::perm::set_permissions(&self.path, HOOK_PERMISSIONS));
Ok(())
}
}
Expand Down Expand Up @@ -179,8 +226,11 @@ impl<'a> HookTable<'a> {
fn load_hook(&self, hook_type: HookType) -> Option<Hook> {
let template = self.package.hook_template_path(&hook_type);
let concrete = self.package.hook_path(&hook_type);

let (user, group) = hab_users::get_user_and_group(&self.package.pkg_install)
.expect("Can't determine user:group");
match fs::metadata(&template) {
Ok(_) => Some(Hook::new(hook_type, template, concrete)),
Ok(_) => Some(Hook::new(hook_type, template, concrete, user, group)),
Err(_) => None,
}
}
Expand Down
Loading