How to access private Docker repository in OpsWorks ECS Layer? - docker

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.

Related

Where is a logical place to put a file flag?

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.

Google app engine: Best practice for hiding Rails secret keys?

I am deploying my Rails app to GAE, whose codes are stored in github.
Obviously, I need to hide my secret key and database password.
In Heroku, I can set them in environment variables very easily and nicely using Heroku GUI, so it won't appear in any source code or database.
What about GAE?
I cannot set them in app.yaml because:
.gitignore is not an option: Even I hide app.yaml file or alternative json file by .gitignore, I have to save it in my local computer. It means that Only I can deploy, and I have to do backup by myself. This is terrible.
Someone says that I can store secret values in database. But I want to hide database password too.
Any idea?
The most secure way to store this info is using project metadata. On a Flexible/ManagedVM environment you can access the metadata via a simple http request.
From the google blog post:
With Compute Engine, Container Engine, and Managed VMs, there is a magic URL you can CURL to get metadata.
ManagedVMs are the old name for what is now called 'AppEngine Flexible Environment'. Since you say you are using Ruby on App Engine you must be using Flexible/ManagedVMs. Therefore you should be able to use these 'magic URLs'.
So to get an application secret called mysecret in Ruby you might do:
Net::HTTP.get(
URI.parse('http://metadata.google.internal/computeMetadata/v1/project/attributes/mysecret'))
(For #joshlf) Here's how to access project metadata on AppEngine Standard Environment in Python:
# Note that the code will not work on dev_appserver,
# you will need to switch to some other mechanism
# for configuration in that environment
# Specifically the project_id will resolve to something
# compute engine API will treat as invalid
from google.appengine.api import app_identity
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
compute = discovery.build(
'compute', 'v1', credentials=GoogleCredentials.get_application_default())
def get_project_metadata(metadata_key):
project_id = app_identity.get_application_id()
project = compute.projects().get(project=project_id).execute()
for entry in project['commonInstanceMetadata']['items']:
if entry['key'] == metadata_key:
return entry['value']
return None
get_project_metadata('my_key')
I addressed this problem in an answer to a similar question. Essentially, you can create a credentials.yaml file alongside your app.yaml and import it in app.yaml. This will allow you to specify your credentials as ENV variables while retaining the ability to ignore the file in git. The includes: tag allows you to import an array of files in your app.yaml.
Example app.yaml:
runtime: go
api_version: go1
env_variables:
FIST_VAR: myFirstVar
includes:
- credentials.yaml
credentials.yaml:
env_variables:
SECOND_VAR: mySecondVar
API_KEY: key-123

sandbox testing environments exist for TDD'ing command line application

I'm writing a command line command but want to TDD it. I'll be creating and deleting files and was wondering if there's a sandbox testing gem or something like that. I'm using ruby and rspec.
Depends on what you're trying to do, but I test most of my command line Ruby by mocking out the file system and STDIN/STDOUT. Using dependency injection I often end up with something along these lines:
describe Add do
it 'writes the result to standard out' do
console = mock('STDOUT')
console.should_receive(:puts).with('5')
Add.new(console).execute(3,2)
end
end
class Add
def initialize(out = STDOUT)
#out = out
end
def execute(command_line_args)
#out.puts(command_line_args.inject(:+))
end
end
Add.new.execute(ARGS)
By using default values I can inject in the test, but leave it out of the production code.
Hope that helps!
Brandon
The template generated by the newgem install_cucumber generator uses a pattern that I like quite a bit. Have a look at the support/env.rb and support/common.rb files it creates:
https://github.com/drnic/newgem/blob/master/rubygems_generators/install_cucumber/templates/features/support/env.rb.erb
https://github.com/drnic/newgem/blob/master/rubygems_generators/install_cucumber/templates/features/support/common.rb
Use of it in test looks like this:
in_tmp_folder do
# The current directory is now a generated tmp folder.
# If you stick to relative paths, everything you do in here should be safe
end
The files linked to above are for using this in cucumber tests, but it could easily be adapter to whatever framework you're using. The env.rb above deletes the tmp folder before each test starts.
You might also want to take a look at the sandbox gem.
gem install sandbox
Example usage is here: https://github.com/bdimcheff/sandbox

Executing System Commands with Rails

I am executing some system commands based on user actions such a mkdir,cd, cp -r skel/ dest/, and creating an apache vhost etc.
Where is the best place for this code to live? My instinct is to put them in the model as private methods, is this correct?
Thx
Jeff
Rails recommend having skinny controllers and fat models, but I believe that executing system commands is irrelevant to the model.
Since they depend of users actions, I'd suggest putting them in a library (/lib) and calling that lib from the controller.
Also, keep in mind that FileUtil might already do what you're looking for.
Instead of directly shelling out, I would advise using the FileUtils module, included with Ruby.
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html
require 'fileutils'
FileUtils.mkdir 'test'
FileUtils.cd 'test'
FileUtils.cp_r 'skel', 'dest'
I would also put them in the model as private methods.

Ruby on Rails: How do I specify a non-relative path to a layout when calling render?

(Rails version 2.3.2)
By default the :layout parameter for render takes a relative path and adds this to the default layout directory ("app/views/layout").
Eg:
render :file => '../resources/website/home_page.html.erb', :layout => '../../../../resources/website/layout'
"If no directory is specified for the template name, the template will by default be looked for in app/views/layouts/. Otherwise, it will be looked up relative to the template root."
-http://api.rubyonrails.org/classes/ActionController/Layout/ClassMethods.html
However, the above only works in development mode, and breaks in production, failing to find the template. Exception: ActionView::MissingTemplate
Either way, I would rather specify the direct path to a layout file.
(The idea is to keep the specified layout file separate from the main project views, in a plugin-like way.)
Is this possible?
I could temporarily (instance only) override the method "default_layout" in ActionController::Layout? (But im not sure how?)
Thanks for reading.
If you need to resolve layout per request, try:
class ApplicationController < ActionController::Base
layout :resolve_layout
# some definitions
protected
def resolve_layout
# some logic depending on current request
path_to_layout = RAILS_ROOT + "/path/to/layout"
return path_to_layout
end
end
I hope, that is what you need.
Probably the only good way to do this would be to make a constant in your environment.rb with the path for whatever box you're on. So something like
LAYOUT_PATH = '/var/www/templates'
The other option would be to keep the templates in the correct directory but use an svn external or the equivalent in your SCM of choice to keep that template directory up to date with all the other sites that use the same templates.
You can probably add to the controller view paths (see here) to allow your app to pick up templates from different directories. This could potentially also cure your other weird template paths.
If you want absolute paths, use RAILS_ROOT, as suggested here. If you want to share views from a plugin, you may also want to check out the rails-engines plugin.
But also remember that Rails (kind of intentionally) makes doing strange things hard. If you don't have a really strong reason to do otherwise, you'll enjoy a smoother ride by sticking to the defaults.

Resources