How to dynamically set phantomJS command line options on Heroku - heroku

I have a phantomjs app running on heroku. I need to be able to set several commands which are normally accessed by the command line (https://github.com/ariya/phantomjs/wiki/API-Reference), preferably at runtime, but if necessary once a day.
I want to set the heroku procfile to:
phantomjs --config=/path/to/config.json somescript.js
where the config.json looks like
{
/* Same as: --ignore-ssl-errors=true */
"ignoreSslErrors": true,
/* Same as: --max-disk-cache-size=1000 */
"maxDiskCacheSize": 1000,
/* Same as: --output-encoding=utf8 */
"outputEncoding": "utf8"
/* etc. */
}
My thought is I would like to upload a json object to the heroku ephemeral filesystem before running my phantomjs app. I'm hoping when it runs it will use the updated config file. Does this seem reasonable? Has anyone tried something like this?

I would set a variable through
heroku config:set NAME=VALUE
which is read at runtime, so you could change it whenever you need to.
You could also update config variables via their API: https://devcenter.heroku.com/articles/platform-api-reference#config-var, if you have the need to change them more often.

Related

Heroku failed to load ./.env

My Problem
I am having trouble loading my environment variables on Heroku production.
When pushing to Heroku I get following error message during the build script:
Failed to load ./.env.
Current Setup
I am using a .env file in the root of my app locally. I can succesfully load my environment variables using the dotenv-webpack plugin as follows:
//webpack.config
const Dotenv = require('dotenv-webpack')
module.exports = {
// other settings...
plugins: [
new Dotenv(),
]
};
Loading the environment variables:
//server.js
require('dotenv').config();
console.log(process.env.MY_VARIABLE);
This works like a charm locally, but fails on Heroku.
Note: My config vars have been set on Heroku, so that's not the problem.
What I tried
I have already tried to force load the .env file from the root of my app like this:
new Dotenv({ path: path.resolve(__dirname, './.env') });
Someone also pointed out that the Heroku environment might be system wide environment variables so I tried to load them using:
new Dotenv({ systemVars: true });
Neither of these attempts worked for me.
My guess
I have noticed that Heroku saves their .env file under ./tmp/build_someRandomBuildId/.env. My guess is that the .env file is not on the root of the directory, hence why dotenv can't find it. There is also no way to hardcode the location of this file in my Webpack configuration as the build ID is randomized with every build. Is there a way to tell Webpack to look for the file in a dynamic location?
Today i stumbled upon this problem, i tried several solutions but none worked. My App was working locally but in production mode (heroku) it was not loading process.env correctly.
then i found this https://www.npmjs.com/package/dotenv-webpack
//webpack.config.js
plugins: [
new Dotenv({ systemvars: true }),
],
Just setting systemvars to true does the trick..
For now I have tested this using different keys for the .env file and the heroku dashboard; They are not connected, and they replace themself correctly in production or dev mode.
Use the package "dotenv-webpack" instead of "dotenv".
I hope this saves some time to anyone facing the same problem
I finally found the solution, leaving this here for others who have the same problem as I did.
I used dotenv-webpack to set my environment variables locally, which worked like a charm. Heroku on the other hand sets their environment variables automatically, so there is no need to set them yourself. There is no need to look for a .env file. All I had to do was split up my webpack.config in 2 separate files.
//webpack.dev
require('dotenv').config();
plugins: [
new Dotenv()
],
Load .env file locally.
//webpack.prod
require('dotenv').config();
plugins: [
new webpack.DefinePlugin({
'process.env': {
'YOUR_VARIABLE': JSON.stringify(process.env.YOUR_VARIABLE),
}
});
]
Get your environment variables from Heroku and write them to your own process.env
If you are not using Webpacks, the idea's solution is similar to the accepted answer.
Heroku works on "production" mode by default, so if the problem in Heroku is with Dotenv (which should not be used anyways in Heroku), disable the use of Dotenv in production time like this:
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config() }
}
...and then, access env variables just by doing:
var someVar = process.env.SOME_VARIABLE;
Don't forget to set the environment variables on Heroku first by using Console Commandline in your app's dashboard, or with an app.json file.

Set host name as an environment variable in Heroku review app

I'm using the Review Apps feature integrated with Github on Heroku. In one of my apps, I set an environment variable called HOST_NAME . For example, if the site is http://www.purplebinder.com, then HOST_NAME would be set to www.purplebinder.com. It's used in a couple of places where we work with cookies and in our transactional emails.
When I open up a new pull request and spin up a review app, HOST_NAME should be something like purplebinder-pr-27.herokuapp.com.
Is there a way to set this value automatically? The Heroku documentation on review apps says an env var can inherit a value from the parent app or be hardcoded in app.json. Neither of those approaches work here, because the value needs to be different each time, and also different from the parent app.
Heroku also says an env var can be set "through a generator", but doesn't go into detail about what that is.
This question might be a duplicate of Setting ROOT_URL for Review Apps, but nobody answered that one. It's also similar to How to get Heroku app name from inside the app, but the answers there involved running a script after the app was created - here I'd like to set this value as part of the initial build.
From https://devcenter.heroku.com/articles/github-integration-review-apps#heroku_app_name-and-heroku_parent_app_name:
To help with scripting, two special config vars are available to
review apps. If you specify HEROKU_APP_NAME or HEROKU_PARENT_APP_NAME
as required or optional config vars in your app.json file, Heroku will
set those config vars to the new application name and the parent
application name respectively. They will then be available for use in
the postdeploy script so that you can do more advanced bootstrapping
and configuration.
Here is an example app.json file that uses
HEROKU_APP_NAME and HEROKU_PARENT_APP_NAME:
{
"name":"Advanced App",
"scripts": {
"postdeploy": "rake db:setup && bin/bootstrap"
},
"env": {
"HEROKU_APP_NAME": {
"required": true
},
"HEROKU_PARENT_APP_NAME": {
"required": true
}
}
}
If you add the heroku-buildpack-cli to your parent app, then it enables you to set environment variables from your post-deploy script. The command should look something like the following:
heroku config:set HOST_NAME=${HEROKU_APP_NAME}.herokuapp.com --app ${HEROKU_APP_NAME}
Here's an approach ignoring app.json for Rails installations:
in the relative config/<environment>.rb. I personally use production.rb and staging just references it.
if ENV.fetch("HEROKU_APP_NAME", "").include?("staging-pr-")
ENV["APPLICATION_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
ENV["ASSET_HOST"] = "https://" + ENV["APPLICATION_HOST"]
config.action_mailer.default_url_options = { host: ENV.fetch("APPLICATION_HOST") }
end
...
It's a bit misleading as the heroku environment variables will still have the old variables, but it works.
You can also create review environment for you application copying staging.rb or production.rb from config/environments. This would be useful.
After adding HEROKU_APP_NAME and HEROKU_PARENT_APP_NAME to your app.json, you can easily set;
config.action_mailer.default_url_options = { host: "#{ENV['HEROKU_APP_NAME']}.herokuapp.com" }
config.action_mailer.asset_host = "http://#{ENV['HEROKU_APP_NAME']}.herokuapp.com"
config.action_controller.asset_host = "#{ENV['HEROKU_APP_NAME']}.herokuapp.com"
config.action_cable.url = "wss://#{ENV['HEROKU_APP_NAME']}.herokuapp.com/cable"

Environment Variables on Heroku and Mailgun Problems with Phoenix Framework

I was following this guide on deploying to Heroku and this one for sending email.
Everything works fine in development. My variables are set in Heroku:
heroku config
...
MAILGUN_DOMAIN: https://api.mailgun.net/v3/xxxxxx.mailgun.org
MAILGUN_KEY: key-3-xxxxxx
...
And loaded from the config files like so:
config :take_two, Mailer,
domain: System.get_env("MAILGUN_DOMAIN"),
key: System.get_env("MAILGUN_KEY")
However when I try to send email on Heroku when the Mailgun config is set from environment variables I get this error:
** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1
(elixir) lib/io.ex:346: IO.chardata_to_string(nil)
(elixir) lib/path.ex:467: Path.join/2
(elixir) lib/path.ex:449: Path.join/1
lib/client.ex:44: Mailgun.Client.send_without_attachments/2
This happens when the domain is not set for the Mailgun Client. But it is supposed to be set from the environment variable. I made a simple module to test:
defmodule TakeTwo.Mailer do
require Logger
use Mailgun.Client,
Application.get_env(:take_two, Mailer)
def blank_shot do
Logger.info Application.get_env(:take_two, Mailer)[:domain]
Logger.info Application.get_env(:take_two, Mailer)[:key]
send_email from: "steve#xxx.com", to: "speggy#xxx.com", subject: "Hello", text: "This is a blank shot"
end
When I run TakeTwo.Mailer.blank_shot I see the correct domain/key variables logged followed by the error. I am not sure how to debug the Mailgun client remotely.
Finally, if I recreate the above module in the shell (after running heroku run iex -S mix) it works just fine!?
I feel like when the original module is being loaded perhaps the environment variables have yet to be loaded??
The answer was a little buried in a comment so I wanted to make it easier to find. As the other answer mentions, the environment variables aren't available, but the buildpack lets you configure them to be:
I created a elixir_buildpack.config file and added the following:
config_vars_to_export=(DATABASE_URL MAILGUN_DOMAIN MAILGUN_KEY SECRET_KEY_BASE)
The environment variables aren't available at build time. I had the same issue and decided to get rid of the macro carrying the configuration. You can use this patch to move on.

How to set Heroku config var with contents of a file

To set config vars for a Heroku app, you do this:
$ heroku config:set GITHUB_USERNAME=joesmith
How would I set a config var with the contents of a file?
Take a look at the heroku-config plugin, which adds a heroku config:push command to push key-value pairs in a file named .env to the app.
It also has a heroku config:pull command to do the opposite and works very well with foreman for running the app locally with the config in .env.
https://github.com/xavdid/heroku-config
Example
heroku config:push --file=.env.production
I know this is too late but still it will be helpful for future users who land here.
I also wanted a quick solution to add variable to heroku app but copy-paste is so boring.. So wrote a script to read values from the .env file and set it at the requested app - all things passed as an option:
https://gist.github.com/md-farhan-memon/e90e30cc0d67d0a0cd7779d6adfe62d1
Usage
./bulk_add_heroku_config_variables.sh -f='/path/to/your/.environment/file' -s='bsc-server-name' -k='YOUR_CONFIG_KEY1 YOUR_CONFIG_KEY2'
A simple pure-python solution using honcho and invoke:
from honcho.environ import parse
from invoke import run
def push_env(file='.env'):
"""Push .env key/value pairs to heroku"""
with open(file, 'r') as f:
env = parse(f.read())
cmd = 'heroku config:set ' + ' '.join(
f'{key}={value}' for key, value in env.items())
run(cmd)
The idea here is that you will get the same configuration as if you ran the project locally using honcho. Then I use invoke to run this task easily from the command line (using #task and c.run) but I've adapted it here to stand alone.

Access current git commit number from within Heroku app

I know the slug compiler removes the .git directory when creating a heroku slug, but is there any way to configure Heroku so that I can access the currently running git commit number from within my scripts?
I'd like to be able to have a small link on my sinatra app (run within Heroku) which says "running version e72fb274a0" (or something similar). How can I retrieve this, or force the slug compiler to add it to an environment variable?
PROGRESS:
I reckon the best way to do this is to make a custom buildpack which writes the git commit version number to the heroku slug before the .git directory is deleted.
I've tried to do this (see my fork of the ruby buildpack) but the line I've added – line 23 – doesn't seem to be doing the job. Heroku sees & uses the new buildpack, but doesn't seem to write the file to the slug.
Anyone have any idea why my custom buildpack isn't working as expected?
Thanks,
JP
A couple of options...
SOURCE_VERSION environment variable (build-time)
Since 1st April 2015, there's a SOURCE_VERSION environment variable available to builds running on Heroku. For git-pushed builds, this is the git commit SHA-1 of the source being built:
https://devcenter.heroku.com/changelog-items/630
(thanks to #srtech for pointing that out!)
An example of me using that variable in a build - if you look at the HTML served by the deployed app, you'll see the commit id is coming though in an HTML comment near the very bottom: https://gu-who.herokuapp.com/
/etc/heroku/dyno metadata file (run-time)
Heroku have beta functionality to write out a /etc/heroku/dyno metadata file onto your running dyno. If you email support you can probably get added to the beta. Here's a place where Heroku themselves are using it:
https://github.com/heroku/fix/blob/6c8ab7a/lib/heroku_dyno_metadata.rb
The contents look like this:
{
"dyno":{
"physical_id":"161bfad9-9e83-40b7-b385-78305db2f168",
"size":1,
"name":"run.7145"
},
"app":{
"id":null
},
"release":{
"id":50,
"commit":"2c3a0b24069af49b3de35b8e8c26765c1dba9ff0",
"description":null
}
}
..so release.commit is the field you're after. I used to use this method until the SOURCE_VERSION variable became available.
In 2018 this is what you want:
https://devcenter.heroku.com/articles/dyno-metadata
heroku labs:enable runtime-dyno-metadata -a <app name>
You can run a script before deploy that store this information (maybe on a YAML)
using these a = `ls` (note that is not ' "apostrophe" sign is ` "inverse accute" sign)
the a variable will have the result of this bash command,so you can do
git = `git log`
and then find the information you want it and store it.
So you will be able to retrieve it later.
Did this helped ?

Resources