I'm trying to test ntp settings.
I've provisioned a VM with ntp services installed.
I'm able to login onto the vm and run a command that verifies ntp is indeed installed and restricts queries:
vagrant#vagrant:~> sudo ntpq -p
localhost: timed out, nothing received
***Request timed out
However, when I try to test this exact command in a test, it returns empty...
I'm obviously missing something crucial here, but I cant figure out what.
Here is my test:
control 'ntp configuration' do
describe command('sudo nptq -p') do
its('stdout') { should match('localhost: timed out, nothing received') }
end
end
And the error:
× ntp configuration: Command: `sudo nptq -p`
× Command: `sudo nptq -p` stdout is expected to match "localhost: timed out, nothing received"
expected "" to match "localhost: timed out, nothing received"
I've tried stdout and stderr, both to no avail.
One thing that I do notice however, is that running this command from the commandline on the vm itself, takes a few seconds to return the message.
The test however, returns in noticeable less time with an empty string.
Could anyone please shed some light on this? :)
Error lies in:
control 'ntp configuration' do
describe command('sudo nptq -p') do
its('stdout') { should match('localhost: timed out, nothing received') }
end
end
Typo in the command -> nptq has to be ntpq, also sudo can be omitted.
The message that was being checked for was actually returned in stderr instead of stdout
Working code:
describe command 'ntpq -p' do
its('stderr') { should match(/localhost: timed out, nothing received/) }
end
Related
so im trying to make an if statement to tell me if an sftp connection was sucessfull or failed, and if its a sucess i want to run a piece of code that automates an sftp download that ive already made.
My problem is that this if statement executes this sftp connection, and then prompts me for a password and stalls the rest of the code.
i wanted to do something like this
if ( sftp -oPort=23 user#server )
then
expect <<-EOF
spawn sftp -oPort=23 user#server
.....
I want to know if its possible for me to make the if statement not execute the sftp connection and then not prompt me , maybe execute it on the background or something.
I would appreciate if someone could tell me if what im asking is possible, or propose a better solution to what im trying to do, thanks
You cannot not-execute a command and then react on the return value of the executed command (because this is what you really want to do: check if you can run sftp successful, and if so do a "proper" run; but you'll never know whether it can run successfull without running it).
So the main question is, what it is what you actually want to test.
If you want to test whether you can do a full sftp connection (with all the handshaking and what not), you could try running sftp in batch-mode (which is handily non-interactive).
E.g. the following runs an sftp session, only to terminate it immediately with a bye command:
if echo bye | sftp -b - -oPort=23 user#server ; then
echo "sftp succeeded"
fi
This will only succeed if the entire sftp session works (that is: you pass any key checks; you can authenticate, ...).
If the server asks you for a password, it will fail to authenticate (being non-interactive), and you won't enter the then body.
If you only want to check whether something is listening on port 23, you can use netcat for this:
if netcat -z server 23; then
echo "port:32 is open"
fi
This will succeed whenever it can successfully bind to port 23 on the server. It doesn't care whether there's an sftp daemon running, or (more likely) a telnet daemon.
You could also do some minimal test whether the remote server looks like an SSH/SFTP server: ssh servers usually greet you with a string indicating that they indeed speak ssh: something like "SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4".
With this information you can then run:
if echo QUIT | netcat server 23 | grep SSH; then
echo "found an ssh server"
fi
I have two ruby blocks at the end of a recipe:
ruby_block 'set permissions for app dir' do
block do
require 'fileutils'
FileUtils.chown_R 'user01', 'user01', '/mnt/app/'
end
action :run
end
ruby_block 'configure node app session' do
block do
cmd = "sudo su - user01 -c \"/mnt/app/http-app-/bin/app create /mnt/app/http-app/#{node['hostname']}\" && sudo su -c 'systemctl enable app' && sudo su -c 'systemctl start app'"
exec(cmd)
end
action :run
not_if "stat -c %U /mnt/app/#{node['hostname']} |grep app"
end
A couple strange things are happening. One, I cannot add any code after the last block... it will not run if added. Two, when the cookbook runs the recipe never ends with if the run failed or was successful. Bootstrapping the system a second time will prove to finish successful... but ssh'ing to the box and running chef-client comes back with an empty run list.
Can anyone explain this behavior? How can i fix it?
exec() is not what you think. That's a Ruby core method which calls the actual exec() syscall, which replaces the current process with something new. What you want is our shell_out!() helper which runs a subcommand and returns and object with the results.
When using Net::SSH to run commands on a remote connection, it adds the following script to the end of each and every command:
DONTEVERUSETHIS=$?; echo #{manager.separator} $DONTEVERUSETHIS; echo \"exit $DONTEVERUSETHIS\"|sh
the output produced looks like:
DONTEVERUSETHIS=$?; echo 10e75e2821012645fa3a3cc08ec5de527a392af68db4c3cac63dac22d4de2a8708fcc176190817fe $DONTEVERUSETHIS; echo "exit $DONTEVERUSETHIS"|sh
Here's a link to the source code Net::SSH::Shell::Process and look at the 'run' method
Can anyone explain why this is always added?
It doesn't appear in the console output but plays hell with parsing ~/.bash_history
A quick look into the source repository reveals this commit:
keep the exitcode 1 available for the next command
In effect, this allows you to inspect the value of $? (i.e. the exitcode of the previous command) in the next command.
TL;DR: It's the machine readable equivalent of a colored shell prompt. It's there to tell the library when the issued command has finished, and whether it was successful.
When running a command with Net::SSH (not ::Shell), here's what happens:
Connection is established
Command is sent
Output is received
The command exits, sshd returns the exit code and ends the connection.
This means that it's easy to:
Get the output: just read until sshd closes the connection.
Get the exit code. sshd returns it.
However, it means that each command is run in a separate session, so cd /tmp followed by pwd will return /home/youruser because these are two different sessions, so the former doesn't affect the latter.
The purpose of Net::SSH::Shell is instead to run multiple, individual commands in the same shell session:
Connection is established.
Commands are sent as a single, infinite, concatenated stream
Output is received as a single, infinite, concatenated stream
This leaves two open questions:
How do you know whether the command has finished or whether it's still processing?
How do you get the exit code now that sshd doesn't return it?
The way Net::SSH::Shell solves this is by modifying the command in the way you saw, to make it print a unique ID and exit code when done:
To get the command's output, read until a line with the unique ID is printed.
To get the exit code, read it from the same line.
I have a Capistrano task that looks like this:
desc "tail log file"
task :tail do
on roles(:app) do
execute "tail -f #{shared_path}/log/#{fetch(:log_file)}.log"
end
end
When I run the task, it proceeds with the blocking tail -f request, but it shows up nothing. I am one hundred percent sure that it simply does not pipe the data somehow (I've verified it - the log file gets updated on the remote) thus it shows nothing. Did I miss something?
The app role is included in the stage config.
Mmmmmmm..., check the permissions in the file system. The user that runs the task should have the permission to read the file.
You can try chmod o+r logfile.log
Here you're giving permissions to read to anybody on the file (Useful for debugging purposes).
I have found a workaround/solution to my problem. I don't remember where I did found the solution, but executing the command rawly by instantiating an ssh connection with a pseudo-tty forced allocation (that's the -t) got it working. That will get the blocking requests like tail -f working. As the man pages say on the -t option:
This can be used to execute arbitrary screen-based programs on a remote machine,
which can be very useful...
def execute_interactively(command)
user = fetch(:user)
port = fetch(:port)
cmd = "ssh -l #{user} #{host} -p #{port} -t 'cd #{deploy_to}/current && #{command}'"
exec cmd
end
You'll need to set the capistrano verbosity level to DEBUG to see any streaming output. I found the solution in the capistrano3-taillog gem; see taillog.cap.
desc "tail log file"
task :tail do
on roles(:app) do
with_verbosity Logger::DEBUG do
execute "tail -f #{shared_path}/log/#{fetch(:log_file)}.log"
end
end
end
def with_verbosity(output_verbosity)
old_verbosity = SSHKit.config.output_verbosity
begin
SSHKit.config.output_verbosity = output_verbosity
yield
ensure
SSHKit.config.output_verbosity = old_verbosity
end
end
I want to accomplish two things:
1) clean out any pointless pid files (if elasticsearch is not running) and then start it, and
2) check that ES has started up before proceeding
Now between what Chef offers out-of-box and what Ruby allows, I can only figure out a pseudo-code like syntax for making it happen but its not going to run so I need some help/advice writing the real thing.
Pseudo-Code For (1):
bash "start it up" do
user "root"
only_if { # pretty sure this syntax is all incorrect, any ideas to make it happen?
(sudo service elasticsearch status).match(/^elasticsearch not running/)
}
code <<-EOS
sudo rm -rf /usr/local/var/run/elasticsearch/*.pid
sudo service elasticsearch restart
EOS
end
Pseudo-Code For (2):
bash "wait for it to start up" do
user "root"
only_if { # pretty sure this syntax is all incorrect, any ideas to make it happen?
(sudo service elasticsearch status).match(/^elasticsearch running with PID/)
}
retries 20
retry_delay 5
code <<-EOS
echo "I can now go on with my life..."
EOS
end
If you wish to ensure a certain particular status before continuing, insert this in a recipe (this is an example and not tested):
service "elasticsearch" do
action [ :enable, :start ]
status_command "/usr/sbin/service elasticsearch status | grep 'running with PID'"
end
It's the job of the init script's start command to wait for the service to be actually started.
Chef docs says:
There is no reason to use the execute resource to control a service because the service resource exposes the start_command attribute directly, which gives a recipe full control over the command issued in a much cleaner, more direct manner.