Removing an item from an array when chef-client is executed - ruby

I am using the firewalld cookbook and having difficulty rewriting the provider code to exclude subnets missing from an array. Below is what the current firewalld provider code looks like. Can some assist with this?
use_inline_resources
action :add do
e = execute "add port #{new_resource.name} to zone" do
not_if "firewall-cmd #{zone} --query-rich-rule=\"#{rich_rule}\"
command(<<-EOC)
firewall-cmd #{zone} --add-rich-rule="#{rich_rule}"
firewall-cmd --permanent #{zone} --add-rich-rule="#{rich_rule}"
EOC
end
new_resource.updated_by_last_action(e.updated_by_last_action?)
end
action :remove do
e = execute "remove port #{new_resource.name} from zone" do
only_if "firewall-cmd #{zone} --query-rich-rule=\"#{rich_rule}\""
command(<<-EOC)
firewall-cmd #{zone} --remove-rich-rule="#{rich_rule}"
firewall-cmd --permanent #{zone} --remove-rich-rule="#{rich_rule}"
EOC
end
new_resource.updated_by_last_action(e.updated_by_last_action?)
end
def zone
new_resource.zone ? "--zone=#{new_resource.zone}" : ''
end
def rich_rule
cmd = "rule "
cmd += "family='#{new_resource.family}' " if new_resource.family
cmd += "source address='#{new_resource.source_address}' " if new_resource.source_address
cmd += "destination address='#{new_resource.destination_address}' " if new_resource.destination_address
cmd += "service name='#{new_resource.service_name}' " if new_resource.service_name
cmd += "port port='#{new_resource.port_number}' protocol='#{new_resource.port_protocol}' " if new_resource.port_number
cmd += "log " if new_resource.log_prefix || new_resource.log_level || new_resource.limit_value
cmd += "prefix='#{new_resource.log_prefix}' " if new_resource.log_prefix
cmd += "level='#{new_resource.log_level}' " if new_resource.log_level
cmd += "limit value='#{new_resource.limit_value}' " if new_resource.limit_value
cmd += new_resource.firewall_action if new_resource.firewall_action
cmd end
My recipe currently looks like this
node['cookbook']['iptables']['subnets'].each do |firewall|
firewalld_rich_rule firewall do
zone firewall["public"]
family firewall["ipv4"]
source_address firewall
firewall_action firewall["accept"]
action :add
end
end
My attributes currently look like this
default["cookbook"]["iptables"]["subnets"] = ["172.16.2.0/24","192.168.1.1/24","10.10.10.0/24"]
The code is currently working as expected. In other words, when i run the cookbook, it populates firewalld with subnets in the attribute array. However when i delete one of the subnets and run the cookbook, it doesn't delete the excluded subnet. Is there a way to write this whereby it automatically deletes any rich rule subnet not in the array?

Related

Mixlib::ShellOut - timeout

I am trying to use Mixlib::ShellOut to execute commands under ruby_block inside a chef recipe.
In Some situations, we cannot complete the task in 600 seconds, and I would like extend further. I have added command in below way,
ruby_block "#{host_short_name}_reg_chef_node" do
block do
puts "Registering Chef Node #{host_full_name}"
_command = "cd #{node['nodeManager']['app']['base_dir']}; #{node['nodeManager']['knife']['binary']} bootstrap --sudo #{host_full_name}"
_command += " --ssh-user #{node['nodeManager']['admin']['user']} --no-host-key-verify --identity-file #{node['nodeManager']['admin']['keyfile']}"
_command +=" --environment #{params[:environment]} --run-list 'role[#{params[:role_hash]['role']}]'"
puts _command
vsphere_output = Mixlib::ShellOut.new(_command, :timeout => 10000)
vsphere_output.run_command
puts "Output: #{vsphere_output.stdout}"
puts "Error : #{vsphere_output.stderr}"
end
action :nothing
end
and I suspect it is not respecting timeout value. Please advise.

How to change rvm gemset over ssh on os x server

ok
I don't know how to change rvm version over ssh under os x server.
What I do:
Login on server over ssh
run script (below) and catch error
Error: 'rvm is not a funciton, many-many-words'
What I have as script:
use File::Spec;
my $server_directory = File::Spec->catfile($ENV{HOME},'MyProject');
my $exec_file = File::Spec->catfile($server_directory,'run_script.rb');
my $run_ruby_script = qq'bundle exec ruby $exec_file'.' '.join(' ',#ARGV);
# reload bash profile
print qx(source $ENV{HOME}/.bash_profile);
print qx(source $ENV{HOME}/.bashrc);
# reload ruby
print qx(source $ENV{HOME}/.rvm/scripts/rvm);
my $ruby_setup = qq([[ -s "$ENV{HOME}/.rvm/scripts/rvm" ]] && source "$ENV{HOME}/.rvm/scripts/rvm");
print $ruby_setup. "\n";
# change directory
chdir($server_directory);
# configure gemset name
my $version = qx(cat .ruby-version);
chomp($version);
my $gemset = qx(cat .ruby-gemset);
chomp($gemset);
my $change_rvm_gemset = qq(rvm use $version\#$gemset);
print qx($ruby_setup && $change_rvm_gemset);
print qx(rvm current);
Ok, after all.
def exec_via_bash(line)
puts %Q(#{line})
exec = 'bash -c "#{line}"'
puts `#{exec}`
end
def RubySetup
# reload bash profile
homedir = ENV['HOME']
exec_via_bash %Q(source #{homedir}/.bash_profile);
exec_via_bash %Q(source #{homedir}/.bashrc);
# reload ruby
exec_via_bash %Q(source #{homedir}/.rvm/scripts/rvm);
ruby_setup = %Q([[ -s "#{homedir}/.rvm/scripts/rvm" ]] && source "#{homedir}/.rvm/scripts/rvm")
puts ruby_setup
ruby_setup
end
if ARGV.empty?
puts "there is not enough arguments passed. maybe you forget ruby file to exec?"
exit(1)
end
ruby_script_path = ARGV.shift;
exec_file_absolute_path = File.expand_path(ruby_script_path)
unless File.exists? exec_file_absolute_path
puts "file #{exec_file_absolute_path} doesn't exists!"
exit(1)
end
exec_file_directory = File.dirname(exec_file_absolute_path)
exec_bundle = %Q'bundle exec ruby #{exec_file_absolute_path}' + ' ' + ARGV.join(' ')
# change directory
Dir.chdir(exec_file_directory);
# print %x(ls);
# configure gemset name
version = %x(cat .ruby-version).strip;
gemset = %x(cat .ruby-gemset).strip;
change_rvm_gemset = %Q(rvm use #{version}\##{gemset});
ruby_setup = RubySetup()
exec_bash_login_line = [ruby_setup, change_rvm_gemset, exec_bundle].join ' && ';
puts 'exec bash login line: ' + exec_bash_login_line
forced = %Q(bash --login -c '#{exec_bash_login_line}');
puts forced, "\n";
puts %x(#{forced});
ok, this script is not a kind of beauty, but it works well.
Example of usage?
ruby script.rb ~/bla/bla/bla/run_your_program.rb --first_argument --second_argument a,b,c --etc
As I said before:
I've already on the server via ssh.
So, I need to run scripts via launchd.
And I should do it with
# part of launchd worker
<string>bash</string>
<string>-c</string>
<string>ruby ~/PathToCharmScript.rb -r a</string>
P.S:
Please, help me with improvements of this script for others!
Here is a gist: wow_this_works

Prompt during Chef provision

Part of a Chef cookbook I'm writing is configuring perforce, which requires the user to enter their password (lest they save this in plaintext in an "attributes" file). Is it possible to interrupt the provisioning with an interactive prompt?
We would prompt the user from the Vagrantfile and then set that value as a Chef attribute. Prompts really only makes sense on dev boxes, so they really shouldn't be part of the Chef recipe:
Vagrant.configure('2') do |config|
config.vm.provision :chef_client do |chef|
chef.add_role 'dev'
chef.chef_server_url = 'https://api.opscode.com/organizations/myorg'
chef.node_name = "vagrant-#{ENV['USER']}-dev.example.com"
chef.validation_key_path = 'example-validator'
chef.json = {
'mysvc' => {
'password' => MySvc.password()
}
}
end
end
module MySvc
def self.password
begin
system 'stty -echo'
print 'MySvc Password: '
; pass = $stdin.gets.chomp; puts "\n"
ensure
system 'stty echo'
end
pass
end
end
Correct me if i misunderstood your problem, if you want to read user input :
You can use built-in SHELL command "read".
example:
[myprompt]$ read -p "Insert text : " IN_TEXT
Insert text : user input
[myprompt]$ echo $IN_TEXT
user input
ps: if you use read command for password you can use "-s" option to hide input coming from terminal.
example2 :
[myprompt]$ read -sp "Insert text : " IN_TEXT
Insert text : //stdin <<"user input"
[myprompt]$ echo $IN_TEXT
user input

Escaping an ampersand character ('&') in a password for a Ruby script

I have a password like 'X&Y' and I am trying to run a Ruby script that opens an SSH session, but the script breaks at the & character like :
*server: X
*server: bash: Y: command not found
Escaping the character like & doesn't help either. Ideas appreciated!
The code where it happens is at the ssh.exec:
pass="X\&Y"
Net::SSH.start( host_name, user, :password => pass ) do |ssh|
#do stuff
command = "sudo -S rm file"
cmd = "#{pass}|#{command}"
ssh.exec(cmd) do |ch, stream, data|
puts "*server:" + data.inspect
end
end
You can use ssh like without & getting any special meaning:
ssh -t -t user#localhost "echo 'abc&def'"
abc&def
Connection to localhost closed.

ruby execute bash command with variables

I need to execute a Bash command in a Ruby script. There are about 6 ways to do this according to "6 Ways to Run Shell Commands in Ruby" by Nate Murray and a few other googled sources.
print "enter myid: "
myID = gets
myID = myID.downcase
myID = myID.chomp
print "enter host: "
host = gets
host = host.downcase
host = host.chomp
print "winexe to host: ",host,"\n"
command = "winexe -U domain\\\\",ID," //",host," \"cmd\""
exec command
For what it's worth you can actually chain those methods, and puts will print a newline for you, so this could just be:
print "enter myid: "
myID = STDIN.gets.downcase.chomp
print "enter host: "
host = STDIN.gets.downcase.chomp
puts "winexe to host: #{host}"
command = "winexe -U dmn1\\\\#{myID} //#{host} \"cmd\""
exec command
It looks like there may have been trouble with how you were putting your command string together.
Also, I had to refer to STDIN directly.
# Minimal changes to get it working:
print "enter myid: "
myID = STDIN.gets
myID = myID.downcase
myID = myID.chomp
print "enter host: "
host = STDIN.gets
host = host.downcase
host = host.chomp
print "winexe to host: ",host,"\n"
command = "echo winexe -U dmn1\\\\#{myID} //#{host} \"cmd\""
exec command
Compact version:
print "enter myid: "
myID = STDIN.gets.downcase.chomp
print "enter host: "
host = STDIN.gets.downcase.chomp
puts "winexe to host: #{host}"
exec "echo winexe -U dmn1\\\\#{myID} //#{host} \"cmd\""
Last two lines with printf style:
puts "winexe to host: %s" % host
exec "echo winexe -U dmn1\\\\%s //%s \"cmd\"" % [myID, host]
Last two lines with plus string concatenation:
puts "winexe to host: " + host
exec "echo winexe -U dmn1\\\\" + myID + " //" + host + " \"cmd\""
Last two lines with C++ style append:
puts "winexe to host: " << host
exec "echo winexe -U dmn1\\\\" << myID << " //" << host << " \"cmd\""

Resources