I understand that we can have vars for particular hosts, and particular groups, how would I idiomatically do the same on a per inventory file basis.
I have 3 inventory files for dev/staging/prod. What is the best way to set vars for these environments. examples would be the stage itself, to be set into /etc/environment for rails, or API keys, or etc.
At this point I have 1 host per env, so I can just set it as host vars, but eventually I wouldn’t be able to scale that.. so I figure there has to be a better way?
If I understand your question correctly, you are unsure how to group hosts and have variables (and perhaps tasks) apply to a group.
Take a look at group_vars and host_vars. This is great for overriding defaults. Here's an example:
group_vars/all:
MAX_MEMORY = 16gb
group_vars/dev
MAX_MEMORY = 2gb
Alternately, you can put "group variables" in your hosts file(s).
Generally speaking, I'd recommend having one playbook; the recipe that you run on dev/QA/production should be as identical as possible to production.
Related
I will host my RoR API-App in the Google App-Engine.
Everything works so far, but I have to store usernames, passwords and keys (e.g. Database user/password) in plain text in the app.yaml. this is just stupid, so I will never be able to push this to my git repo! Usually I store stuff like this in an env variable and use them in my application.
But I did not find a way to set or access env variables.
Is there a way or an alternative to do so?
I did it!
For local development, I just set my env as usual.
If the mode is Production I load them from the Google Datastore all key values pairs and set them as an env variable.
I do this in an Initializer, to do so just create a file in YourApp/config/initializers/ and put the code in it! Just Create new Entities copy the Kind name in the code and set your project id. As your App is hosted in Google it should have access to the datastore (You need to set the right in the IAM-Manager)
require "google/cloud/datastore"
# Load the enviroment variables from the google datastore!
if Rails.env == "production"
data_store = Google::Cloud::Datastore.new(
project_id: 'YOUR_PROJECT_ID'
)
query = data_store.query "YOUR_KIND_NAME"
results = data_store.run query
puts "Set custom env variables!"
# Set each result as an env variable
results[0].properties.to_h.each do |key, value|
ENV[key]= value
end
end
As mentioned in Best practices for managing credentials, you may use an environment variable pointing to credentials outside of the application's source code, such as Cloud Key Management Service. I also recommend to take a look at Secret management with Cloud KMS documentation which explains solutions when you choose a secret management.
In a Ruby on Rails application, where would the most logical place be to put a "file flag."
I am attempting to externalize configuration and allow the presence of a file to be the deciding factor on whether or not something shows on the webapp.
Right now, I have a file here:
lib/
deployment_enabled
Model deployment.rb
class Deployment...
...
def deployment_enabled?
Dir["#{Rails.root}/lib/deployment_enabled"].any?
end
end
Now this works of course, but i'm not sure this follows the MVC paradigms, since the lib directory should consist of scripts. I could put it in config, but again - not sure it belongs there as rails uses this for rails specific configuration, not necessarily the webapp.
I could of course put this in our database, but that require a new table to be created, and that seems unnecessary.
Where's the most logical place to put this flag file? Does Rails have a directory that's created during the generation to put these sort of files?
I suggest using the Rails tmp directory for this purpose. Then:
File.exist?("#{Rails.root}/tmp/deployment_enabled")
Phusion Passenger use this kind of mechanism too.
https://www.phusionpassenger.com/library/walkthroughs/basics/ruby/reloading_code.html#tmp-always_restart-txt
I recommend that you follow the Twelve-Factor App guidelines and keep your code separate from your configuration. In this case you are really talking about a simple boolean value, and the presence of the file is just the mechanism you use to define the value. This should be done instead through an environment variable.
Something like:
DEPLOYMENT_ENABLED=1 RAILS_ENV=production rails server
You would then use an initializer in Rails to detect the value:
# config/initializers/deployment.rb
foo if ENV['DEPLOYMENT_ENABLED']
The value can still be modified at runtime, e.g., ENV['DEPLOYMENT_ENABLED'] = 0.
I am trying to use an ECS Ops-Works layer to manage some automation, but I cannot figure out how to set up those instances to set up the ecs.config to contain my private Docker repository credentials, as one would do manually if managing ec2 jobs directly. I think I need to somehow use some custom Chef to override the setup recipe to load my template rather than the default template for that file, but I am new to Chef so how to do this is unclear.
So to restate the problem, you want to modify this template in the opsworks_ecs::setup recipe:
template "ecs.config" do
path "/etc/ecs/ecs.config"
source "ecs.config.erb"
owner "root"
group "root"
mode 0644
end
I don't know how you are 'calling' this but I'll assume for now that you're either putting this recipe directly in your run_list and/or calling it explicitly with include_recipe "opsworks_ecs::setup"
In that case, write a wrapper cookbook. If you work for "Acme, Org" it might be something like acme_opsworks_ecs::setup.
acme_opsworks_ecs/metadata.rb should at least have:
name 'acme_opsworks_ecs'
version '0.0.1'
depends 'opsworks_ecs'
acme_opsworks_ecs/recipes/setup.rb should look like:
include_recipe "opsworks_ecs::setup"
resources(template: "ecs.config").cookbook(cookbook_name)
acme_opsworks_ecs/templates/default/ecs.config.erb is also required
/* add your own template content to this file -- copy theirs and edit */
That should allow you to fix it. What you're doing is using Chef's two-pass parser so that the opsworks recipe defines the template resource, then you re-open it and edit it, before it actually runs. Now, wherever you have referenced opsworks_ecs::setup in your run_list or include_recipe calls, replace that recipe with acme_opsworks_ecs::setup.
If you don't directly call opsworks_ecs::setup, then wrap the opsworks recipe(s) that you do call instead following the same pattern.
If you google "chef-rewind" you can find more information about this kind of pattern of using chef. Note that the syntax that I used is built-in to chef though and does not require a custom gem install or chef_rewind resource/definition to use, so it will be substantially simpler to use the syntax in this answer.
There's a lot of suggestions on where to store your application wide variables, including a few gems that do it for you. For Rails 4 the most simple way I've found to do this is to add a variable to 'config' in either Application.rb or an initializers/file.rb like such
#/config/application.rb
config.new_variable = 5
or
#/config/initializers/application_variables.rb
Rails.application.config.new_variable = 5
I'm wondering if there's any difference in these two, maybe load times, or if the one in application gets called everytime the application is refreshed, etc...
This definitely depends on the intended usage. I would use /config/application.rb to only configure the actual Rails application. Not to store miscellaneous variables used in my own code. Thats just a global in disguise.
For API keys and other secret bits and bobs the answer is using environmental variables combined with initializers:
# /config/initializers/boozehound_client
# a fictional API client
Boozehound.configure(
api_key: ENV['BOOZEHOUND_API_KEY'],
secret: ENV['BOOZEHOUND_API_SECRET']
)
Otherwise if you need to use a variable across controllers you could place it your ApplicationController.
I need to store app specific configuration in rails. But it has to be:
reachable in any file (model, view, helpers and controllers
environment specified (or not), that means each environment can overwrite the configs specified in environment.rb
I've tried to use environment.rb and put something like
USE_USER_APP = true
that worked to me but when trying to overwrite it in a specific environment it wont work because production.rb, for instance, seems to be inside the Rails:Initializer.run block.
So, anyone?
Look at Configatron: http://github.com/markbates/configatron/tree/master
I have yet to use it, but he's actively developing it now, and looks quite nice.
I was helping a friend set up the solution mentioned by Ricardo yesterday. We hacked it a bit by loading the YAML file with something similar to this (going from memory here):
require 'ostruct'
require 'yaml'
require 'erb'
#config = OpenStruct.new(YAML.load_file("#{RAILS_ROOT}/config/config.yml"))
config = OpenStruct.new(YAML.load(ERB.new(File.read("#{RAILS_ROOT}/config/config.yml")).result))
env_config = config.send(RAILS_ENV)
config.common.update(env_config) unless env_config.nil?
::AppConfig = OpenStruct.new(config.common)
This allowed him to embed Ruby code in the config, like in Rhtml:
development:
path_to_something: <%= RAILS_ROOT %>/config/something.yml
The most basic thing to do is to set a class variable from your environment.rb. I've done this for Google Analytics. Essentially I want a different key depending on which environment I'm in so development or staging don't skew the metrics.
This is how I did it.
In lib/analytics/google_analytics.rb:
module Analytics
class GoogleAnalytics
##account_id = nil
cattr_accessor :account_id
end
end
And then in environment.rb or in environments/production.rb or any of the other environment files:
Analytics::GoogleAnalytics.account_id = "xxxxxxxxx"
Then anywhere you ned to reference, say the default layout with the Google Analytics JavaScript, it you just call Analytics::GoogleAnalytics.account_id.
I found a good way here
Use environment variables. Heroku uses this. Remember that if you keep configuration in the codebase, anyone with access to the code has access to any secret configuration (aws api keys, gateway api keys, etc).
daemontool's envdir is a good tool for setting configuration, I'm pretty sure that's what Heroku uses to give application their environment variables.
I have used Rails Settings Cached.
It is very simple to use, keeps your configuration values cached and allows you to change them dynamically.