Allow env vars to be passed from plan to runtime

I’ve seen a pattern emerging in several of my plans where I am using the same env vars in my plan and in my run/init hooks. I think it would be pretty cool to be able to specify env vars that ship with your artifact and are available when your package runs.

Thats an interesting idea. I think that perhaps there was an RFC about this on GH. I’ll have to look for it though. Do you have a concrete example you’d be able to share here for people who don’t know what you mean?

The example that I run across quite often is the LD_LIBRARY_PATH. Here is an example of having to set that in the run hook of a plan in core: https://github.com/habitat-sh/core-plans/blob/master/ruby-rails-sample/hooks/run#L5

It would be cool to say:

pkg_name=myplan pkg_path_exports=( LD_LIBRARY_PATH=$(pkg_path_for core/gcc-libs)/lib MY_CUSTOM_VAR=awesome_var ) }

I think the idea is good, but I still don’t see why we need it too much. There’s not much the same between build time and run time (i guess from my limited scope).

Although, the LD_LIBRARY_PATH is an interesting one. But this is saying that our binaries we compiled aren’t immutable. The rpath should have been set in stone during build time which makes this var during runtime is not truly needed.

Other things to consider, it might be not so clear as to whats happening during run-time and we may confuse this variable for things that should only happen during build time or vice versa. Right now, I like the fact that plan.sh is primarily used just for building and packaging my binaries. And I like the fact that I have stuff dedicated for run-time like hooks and config stuff are strictly for run-time. Very clear division of responsibilities and keeps me laser focused.

I am a huge +1 to the idea of being able to set some aspects of the runtime environment at build time.

In packaging a Rails application, I’ve had to set many environment variables to appease the expectations of the Ruby ecosystem. I think of every usage of hab pkg path there a smell because they will return the path to the latest version of the dependency on a system, not the version of the dependency my package release was built against.

Along Elliot’s idea, it would be splendiferous if I could declare something like what’s below and then benefit from (1) the run hook getting generated for me and (2) my runtime environment is using the exact same versions of the dependencies I built against. As I understand it, the latter—pinned down runtime dependencies—is one of the guiding principles of the design of Habitat.

pkg_svc_run="./bin/rails server -b {{cfg.rails_binding_ip}} -p {{cfg.rails_port}}"
pkg_svc_exports=(
  SUPERMARKET_DATA="{{pkg.svc_data_path}}"
  GEM_HOME="${SUPERMARKET_DATA}/dist/vendor/bundle/ruby/2.3.0"
  GEM_PATH="$(hab pkg path core/ruby)/lib/ruby/gems/2.3.0:$(hab pkg path core/bundler):$GEM_HOME"
  LD_LIBRARY_PATH="$(hab pkg path core/gcc-libs)/lib"
  PATH="$PATH:${SUPERMARKET_DATA}/dist/bin"
  SSL_CERT_FILE="$(hab pkg path core/cacerts)/ssl/certs/cacert.pem"
  RAILS_ENV="production"
)

Possible implementation: a file written out with the computed exports that is sourced by the generated run hook. That leaves the option for sourcing the exports when a package author needs to write their own run hook.

I was noodling on this - I think we should come up with a syntax that lets these some of these exports come from the upstream. For example, SSL_CERT_FILE - what if that came from the core/cacerts package directly?

For example:

# cacerts plan
build() {
  add_pkg_svc_export SSL_CERT_FILE $pkg_prefix/ssl/certs/cacert.pem
  add_pkg_build_export SSL_CERT_FILE $pkg_prefix/ssl/certs/cacert.pem
}

Followed later by

# openssl
pkg_deps=(core/cacerts)

Would result in SSL_CERT_FILE being set automatically, both at build and at runtime, simply by importing the dep. I think we might need a bit of logic to deal with appending to an array, but otherwise, this might be sweet. It puts the burden in the right spot (cacerts) to export the variables it needs to work with any possible dependency.

I definitely like the distinction between build and runtime exports.

I’d love to see a solution that worked not just when packages are invoked as services with hooks, but also when you execute arbitrary binaries within a package with hab pkg exec or hab pkg binlink. The term svc probably should be avoided for this because any executable in a package will need the same env, not just the pkg_svc_run.

Also +1 to dependencies being able to “export” env vars for setting or appending as in the cacerts example