Test Kitchen - How can I pass the local user login in as a Chef attribute? - ruby

Our development environment includes local VMs running queries to larger, shared resources in the cloud.
It was set up in such a way that the local user's login would be passed into a Chef role as an attribute, which is used to define SSH and DB connections.
We currently use Ruby in the Vagrantfile to pluck out the login and vm.provision to create a /tmp file on the guest VM's filesystem. Our Chef role for the local VMs reads the contents of that file and passes the value into an attribute.
Vagrantfile:
# -*- mode: ruby -*-
# vi: set ft=ruby :
(snip)
require 'etc'
user = Etc.getlogin
(snip)
analytics.vm.provision :shell, inline: "echo #{user} > /tmp/remote_user"
During the Chef run, The contents of /tmp/remote_user are read by the following:
remote_user = File.open("/tmp/remote_user", "r").read.strip
sandbox = "_#{remote_user}"
default_attributes "remote_user" => remote_user,
"sandbox" => sandbox,
Is there a better way to add the current user's login as an attribute to a local Chef run?
If not, how can I replicate the functionality I had in our old Vagrantfile in a .kitchen.yml?

Test Kitchen processes .kitchen.yml via ERB, so you could just simply put something like this in your ERB file:
attributes:
foo: <%= ENV['STUFF'] %>
And then node['foo'] would contain $STUFF. Switch STUFF to USER in your case.

Related

Mina Deploy uses wrong user

I got some issue with the gem 'mina'. If I do set :user, 'username', he tries to connect to the server via Username#xxx.... wich is not working if the user is not existing. My PC is name Username. So mina setup and mina deploy are not working.
Does someone know a solution?.
Thanks
Best regards
Matze
EDIT:
Gemfile:
gem 'mina'
After that I run bundle install and mina init
deploy.rb:
require 'mina/rails'
require 'mina/git'
# require 'mina/rbenv' # for rbenv support. (https://rbenv.org)
require 'mina/rvm' # for rvm support. (https://rvm.io)
# Basic settings:
# domain - The hostname to SSH to.
# deploy_to - Path to deploy into.
# repository - Git repo to clone from. (needed by mina/git)
# branch - Branch name to deploy. (needed by mina/git)
set :user, "user"
set :application_name, 'appname'
set :domain, 'xx.xxx.xxx.xxx'
set :deploy_to, '/var/www/user/appname'
set :repository, 'user#xx.xxx.xxx.xxx:/home/user/git/appname.git'
set :branch, 'master'
# Optional settings:
# set :user, 'user' # Username in the server to SSH to.
# set :port, '30000' # SSH port number.
# set :forward_agent, true # SSH forward_agent.
# Shared dirs and files will be symlinked into the app-folder by the 'deploy:link_shared_paths' step.
# Some plugins already add folders to shared_dirs like `mina/rails` add `public/assets`, `vendor/bundle` and many more
# run `mina -d` to see all folders and files already included in `shared_dirs` and `shared_files`
# set :shared_dirs, fetch(:shared_dirs, []).push('public/assets')
set :shared_files, fetch(:shared_files, []).push('config/database.yml', 'config/secrets.yml')
# This task is the environment that is loaded for all remote run commands, such as
# `mina deploy` or `mina rake`.
task :remote_environment do
# If you're using rbenv, use this to load the rbenv environment.
# Be sure to commit your .ruby-version or .rbenv-version to your repository.
# invoke :'rbenv:load'
# For those using RVM, use this to load an RVM version#gemset.
# invoke :'rvm:use', 'ruby-1.9.3-p125#default'
end
# Put any custom commands you need to run at setup
# All paths in `shared_dirs` and `shared_paths` will be created on their own.
task :setup do
# command %{rbenv install 2.3.0 --skip-existing}
end
desc "Deploys the current version to the server."
task :deploy do
# uncomment this line to make sure you pushed your local branch to the remote origin
# invoke :'git:ensure_pushed'
deploy do
# Put things that will set up an empty directory into a fully set-up
# instance of your project.
invoke :'git:clone'
invoke :'deploy:link_shared_paths'
invoke :'bundle:install'
invoke :'rails:db_migrate'
invoke :'rails:assets_precompile'
invoke :'deploy:cleanup'
on :launch do
in_path(fetch(:current_path)) do
command %{mkdir -p tmp/}
command %{touch tmp/restart.txt}
end
end
end
# you can use `run :local` to run tasks on local machine before of after the deploy scripts
# run(:local){ say 'done' }
end
# For help in making your deploy script, see the Mina documentation:
#
# - https://github.com/mina-deploy/mina/tree/master/docs
set :execution_mode, :exec if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
When I run now mina setup he print that:
$ mina setup
User#xx.xxx.xxx.xxx's password:
SSH Auth key working fine and git working fine he just puts User instead of user before the ip, what is not working because the user just exists with small letter. But my working machine is named User.

Is it possible to load a Vagrantfile config from within another Vagrantfile?

Vagrant Multi-Machine functionality seems pretty cool, however one thing that bothers me (or is isn't immediately apparent) is that there doesn't seem to be a good way to share configuration options between a "parent" Vagrantfile and "children" Vagrantfiles. Is there a way to effectively and maintainably share configuration options between the parent and it's children? An example might make this more clear.
Let's assume I've got a platform which is comprised of 3 apps/services: API, Web, and Worker.
Let's presume a directory structure of the following:
/some_platform
/api
# app code...
Vagrantfile
/web
# app code...
Vagrantfile
/worker
# app code...
Vagrantfile
Vagrantfile
Let's say /some_platform/api/Vagrantfile looks like:
Vagrant.configure("2") do |config|
config.vm.box = "debian/jessie64"
end
Presumably the web and worker Vagrantfiles look similar.
Now, using the wonders of Multi-Machine I rely on Vagrant coordinate these VMs, and /some_platform/Vagrantfile looks like:
Vagrant.configure("2") do |config|
config.vm.define "web" do |api|
api.vm.box = "debian/jessie64"
end
config.vm.define "web" do |web|
web.vm.box = "debian/jessie64"
end
config.vm.define "web" do |worker|
worker.vm.box = "debian/jessie64"
end
end
I realize this example is contrived, but it's easy to see how once you get more and more complex config declarations, it's annoying and hazardous to have that config duplicated in two places.
You might be wondering "Why does each project have it's own Vagrantfile?" Doing so provides a single source of truth for how the server that app runs on should be setup. I realize there are provisioners you can use (and I will use them), but you still have to declare a few other things outside of that and I want to keep that DRY so that I can either bring up a cluster of apps via Multi-Machine, or I can work on a single app and change it's VM/server setup.
What I'd really love is a way to merge other Vagrantfiles into a "parent" file.
Is that possible? Or am I crazy for trying? Any clever ideas on how to achieve this? I've mucked about with some yaml files and POROs to skate around this issue, but none of the hacks feel very satisfying.
Good news!
You can in fact apply DRY principles in a Vagrantfile.
First: Create a file /some_platform/DRY_vagrant/Vagrantfile.sensible to hold some sensible defaults :
Vagrant.configure("2") do |config|
# With the setting below, any vagrantfile VM without a 'config.vm.box' will
# automatically inherit "debian/jessie64"
config.vm.box = "debian/jessie64"
end
Second: Create a file /some_platform/DRY_vagrant/Vagrantfile.worker for the 'worker' virtual machine :
Vagrant.configure("2") do |config|
config.vm.define "worker" do |worker|
# This 'worker' VM will not inherit "debian/jessie64".
# Instead, this VM will explicitly use "debian/stretch64"
worker.vm.box = "debian/stretch64"
end
end
Finally: Create a file /some_platform/Vagrantfile to tie it all together :
# Load Sensible Defaults
sensible_defaults_vagrantfile = '/some_platform/DRY_vagrant/Vagrantfile.sensible'
load sensible_defaults_vagrantfile if File.exists?(sensible_defaults_vagrantfile)
# Define the 'api' VM within the main Vagrantfile
Vagrant.configure("2") do |config|
config.vm.define "api" do |api|
# This 'api' VM will automatically inherit the "debian/jessie64" which we
# configured in Vagrantfile.sensible
# Make customizations to the 'api' VM
api.vm.hostname = "vm-debian-jessie64-api"
end
end
# Load the 'worker' VM
worker_vm_vagrantfile = '/some_platform/DRY_vagrant/Vagrantfile.worker'
load worker_vm_vagrantfile if File.exists?(worker_vm_vagrantfile)
This approach can be used for almost any other vagrantfile config options. It is not limited to just the "config.vm.box" setting.
Hope this helped!
There are 2 things you can look at (probably more, but those two comes to my mind)
look at How to template Vagrantfile using Ruby? its an example how you can read the content of another file, Vagrantfile is just a ruby script so you can use all the power of ruby.
vagrant has a concept of loading and merging, see from doc so if you wanted to do something anytime you run a vagrant command, you could create a Vagrantfile under your ~/.vagrant.d/ folder and it will always run
one drawback (or at least to pay attention) : the Vagrantfile is a ruby script that is evaluated each (and every time) a vagrant command is executed (up, status, halt ....)

Ruby Gem: Install configuration files to the user-home directory

I have to make a REST-Client in Ruby.
The client must be runnable from the command-line like a binary and also it must be "requirable" in a ruby script and provide different functions.
My gemspec does exactly what it should.
But i have no idea how to install a configuration file (YAML) in the user-home folder?
The config file should be in the user directory to provide easy access for the user.
Is this even possible?
Should i check on the first run if there is a config file and create it?
Can i execute an own installation routine while installing a gem?
I did exactly the same thing in Python and it worked fine, so the Ruby client should behave similar.
For such decisions, I wrote gem persey. If you look at the description of the use of this gem, you can see that it provides what you expect:
# Rails.root are not initialized here
app_path = File.expand_path('../../', __FILE__)
# ...
# config with secret keys
# you don't want store this config in repository and copy to secret folder on host machine
my_secret_key_config = '/home/user/secret/keys.yml'
# ...
# Persey.init ENV["environment"] do # set current environment
Persey.init Rails.env do # set current environment
source :yaml, my_secret_key_config, :secret # no comments. It's secret!
env :production do
# ...
end
env :development, :parent => :production do
# ...
end
end

Adding to the Chef Gem Source?

My organization works entirely within the firewall (i.e, no machines have internet access). Whenever chef cookbooks are update and require gems the recipes fail due to the fact they cannot download and install gems from rubygems.org.
We self host copies of required gems - how can we add a custom internal source to chef, so that we don't have to deal with failures?
You can manage the gemrc for the embedded Ruby with Chef Client.
chef_etc_dir = Chef::Util::PathHelper.join(Chef::Config.embedded_dir, 'etc')
chef_gemrc = Chef::Util::PathHelper.join(chef_etc_dir, 'gemrc')
directory chef_etc_dir do
owner "root"
group "root"
mode "0755"
end.run_action(:create)
file chef_gemrc do
owner "root"
group "root"
mode "0644"
content <<EOF
---
:sources:
- https://path.to.internal.repo/
- https://rubygems.org
:update_sources: true
EOF
end.run_action(:create)
The PathHelper methods should give appropriate paths for either Windows or Linux.
The ".run_action(:create)" addition executes the resources at compile time, not converge time, to ensure subsequent chef_gem resources will have access to the newly-managed gemrc at converge time.
Update: Chef appears to recommend the rubygems cookbook to perform this functionality.
gemrc :global do
values(
sources: %w{ https://path.to.internal.repo https://rubygems.org }
)
end

Vagrant not able to find home/vagrant/hiera.yaml

I have inherited a python app that uses Puppet, Vagrant and VirtualBox to provision a local Centos test machine.
This app was written on Mac and I'm developing on Windows.
When I run vagrant up I see a large list of command line errors, the most relevant of which is:
Running Puppet with site.pp..
Warning: Config file /home/vagrant/hiera.yaml not found, using Hiera defaults
WARN: Fri Apr 25 16:32:24 +0100 2014: Not using Hiera::Puppet_logger. It does not report itself to b
e suitable.
I know what Hiera is, and why it's important, but I'm not sure how to fix this.
The file hiera.yaml is present in the repo but it's not found at home/vagrant/hiera.yaml, instead it's found at ./puppet/manifests/hiera.yaml.... Similarly if I ssh into the box, there is absolutely nothing whatsoever inside home/vagrant but I can find this file when I look in /tmp
So I'm confused, is vagrant looking inside the Virtual box and expecting this file to be found at home/vagrant/hiera.yaml? Or have I inherited an app that did not work properly in the first place? I'm really stuck here and I can't get in touch with the original dev.
Here are some details from my Vagrantfile:
Vagrant.configure("2") do |config|
# Base box configuration ommitted
# Forwarded ports ommitted
# Statically set hostname and internal network to match puppet env ommitted
# Enable provisioning with Puppet standalone
config.vm.provision :puppet do |puppet|
# Tell Puppet where to find the hiera config
puppet.options = "--hiera_config hiera.yaml --manifestdir /tmp/vagrant-puppet/manifests"
# Boilerplate Vagrant/Puppet configuration
puppet.module_path = "puppet/modules"
puppet.manifests_path = "puppet/manifests"
puppet.manifest_file = "site.pp"
# Custom facts provided to Puppet
puppet.facter = {
# Tells Puppet that we're running in Vagrant
"is_vagrant" => true,
}
end
# Make the client accessible
config.vm.synced_folder "marflar_client/", "/opt/marflar_client"
end
It's really strange.
There's this puppet.options line that tells Puppet where to look for hiera.yaml and currently it simply specifies the file name. Now, when you run vagrant up, it mounts the current directory (the one that has the Vagrantfile in it) into /vagrant on the guest machine. Since you're saying hiera.yaml is actually found in ./puppet/manifests/hiera.yaml, I believe you want to change the puppet.options line as follows:
puppet.options = "--hiera_config /vagrant/puppet/manifests/hiera.yaml --manifestdir /tmp/vagrant-puppet/manifests"
To solve this warning, you may first try to check from where this file is referenced, i.e.:
$ grep -Rn hiera.yaml /etc/puppet
/etc/puppet/modules/stdlib/spec/spec_helper_acceptance.rb:13: on hosts, '/bin/touch /etc/puppet/hiera.yaml'
/etc/puppet/modules/mysql/spec/spec_helper_acceptance.rb:34: shell("/bin/touch #{default['puppetpath']}/hiera.yaml")
In this case it's your vagrant file.
You may also try to find the right path to it via:
sudo updatedb && locate hiera.yaml
And either follow the #EvgenyChernyavskiy suggestion, create a symbolic link if you found the file:
sudo ln -vs /etc/hiera.yaml /etc/puppet/hiera.yaml
or create the empty file (touch /etc/puppet/hiera.yaml).
In your case you should use the absolute path to your hiera.yaml file, instead of relative.
The warning should be gone.

Resources