docker api ContainerExecInspect cannot get correct exit code - linux

I am using docker engine-api(github.com/docker/engine-api) to execute some command
I use client.ContainerExecCreate and then client.ContainerExecInspect to run my command and then get the command exit code(I run multiple commands in the same container so the exit code get from ContainerInspect is useless for me.)
This is my function use to execute command in container
http://pastebin.com/rTNVuv9T
but ContainerExecInspect return wrong values sometime, because sometimes ContainerExecInspect is called before the command exit and it said exit code is zero, which is wrong
And I wrote a testcase to test it
http://pastebin.com/PED1Rf4k
And the result will not be 233, it will be 0
I have set ExecConfig.Detach = true and ExecStartCheck.Detach = true, but no helps
Is there any way to wait until the command exit then get the exit code?
Addition:
For some of my command running is shell script not a executable, so I think I need to prefix /bin/bash, and wait the container exit, is not what I want, I want to wait the command exit, and the container is still running

I think now I can solve my problem
The main point is when using containerExecAttach it will exposed the hijacked connection and, I can judge whether the command exit by read from the connection until EOF
There are a few point to set then
Should set ExecConfig AttachStdout to true
Then read from hijacked conn
Here is a sample code
atinfo, err := cli.ContainerExecAttach(ctx, execID, ec)
// error handling
defer atinfo.Close()
c = atinfo.Conn
one := make([]byte, 1)
_, err = c.Read(one)
if err == io.EOF {
println("Connection closed")
}
This will wait until the command execute complete
ExecConfig is set to
ec.Detach = false
ec.Tty = false
ec.AttachStdout = true

Related

How do I run an external file in soapui and take the output and set it as header

I would like to run an external .bat file using groovy script in soapUI. also would like to use the output generated from the external file as the value for the header
here is the script that I am using to run the bat file
String line
def p = "cmd /c C:\\Script\\S1.bat".execute()
def bri = new BufferedReader (new InputStreamReader(p.getInputStream()))
while ((line = bri.readLine()) != null) {log.info line}
here is the content of the bat file
java -jar SignatureGen.jar -pRESOURCE -nRandomString -mGET -d/api/discussion-streams/metadata -teyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJjbGllbnQiOiIxIiwicm9sZSI6IllGQURNSU4iLCJleHAiOjI3NTgzMjU2MDIsInRpIjo3MjAwNiwiaWF0IjoxNTU4MzI1NjAyLCJwZXJzb24iOiI1In0.bbci7ZBWmPsANN34Ris9H0-mosKF2JLTZ-530Rex2ut1kjCwprZr_196N-K1alFBH_A9pbG0MPspaDOnvOKOjA
The following code:
def p = "ls -la".execute()
def err = new StringBuffer()
def out = new StringBuffer()
p.waitForProcessOutput(out, err)
p.waitForOrKill(5000)
int ret = p.exitValue()
// optionally check the exit value and err for errors
println "ERR: $err"
println "OUT: $out"
// if you want to do something line based with the output
out.readLines().each { line ->
println "LINE: $line"
}
is based on linux, but translates to windows by just replacing the ls -la with your bat file invocation cmd /c C:\\Script\\S1.bat.
This executes the process, calls waitForProcessOutput to make sure the process doesn't block and that we are saving away the stdout and stderr streams of the process, and then waits for the process to finish using waitForOrKill.
After the waitForOrKill the process has either been terminated because it took too long, or it has completed normally. Whatever the case, the out variable will contain the output of the command. To figure out whether or not there was an error during bat file execution, you can inspect the ret and err variables.
I chose the waitForOrKill timeout at random, adjust to fit your needs. You can also use waitFor without a timeout which will wait until the process completes, but it is generally better to set some timeout to make sure your command doesn't execute indefinitely.

How to ask for user input when running ruby code on remote server with capistrano?

I want to confirm the action when running a capistrano task on a remote server:
task :do_someting do
on roles(:primary) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :rails, :runner,
%Q['require "do_something"; Do::Something.()']
end
end
end
end
Where `DoSomethig looks like this:
require "highline/import"
class DoSomething
def self.call
query_db_for_objects.each do |obj|
answer = ask "Are you sure to do something with #{obj}? (y/n)"
rerun unless answer == 'y'
do_something
end
end
end
Method ask from highline gem doesn't seem to work when asking from a remote server and the command bundle exec cap production do_something hangs forever.
How can I ask for a user input from a remote server when running this capistrano task?
I was able to read the user answer from a remote server with the following ruby code
task :do_someting do
class ConfirmHandler
def on_data(command, stream_name, data, channel)
if data.to_s =~ /\?$/
prompt = Net::SSH::Prompt.default.start(type: 'confirm')
response = prompt.ask "Please enter your response (y/n)"
channel.send_data "#{response}\n"
end
end
end
on roles(:primary) do
within release_path do
with rails_env: fetch(:rails_env) do
execute :rails, :runner,
%Q['require "do_something"; Do::Something.()']
end
end
end
end
where Do::Something has ask_user method which looks the following way:
class Do::Something
def self.call
answer = ask_user
puts "Answer is: #{answer}"
end
def self.ask_user
puts 'Do something?'
`read response; echo $response`
end
end

How to check if a method returns a non zero exit code in Groovy

I have a Jenkinsfile project that requires me to include an 'if statement to ascertain if shell commands within certain methods return an exit code outside of 0.
The first method method 1 works as expected. However i would like to include an if statement to skip the second stage since that shell command in method 2 doesn't exit with 0.
def method1(setup){
sh """
echo ${setup}
"""
}
def method2(setup){
sh """
ech ${setup}
"""
}
node {
stage('print method1'){
method1('paul')
}
// I need an if statement to skip this method since the if statement returns non=zero
stage('This method should be skipped'){
if(method2 returns != 0) //This if condition fails but need something similar to this
method1('paul')
}
}
Any help with this is much appreciated.
You use a default sh step execution in your example which means that exit code is not returned from the command. If exist status is something else than 0 in such case, pipeline fails with the exception. If you want to return exit status and allow the pipeline to continue you have to pass returnStatus: true option, for instance:
int status = sh(script: """
echo ${setup}
""", returnStatus: true)
if (status != 0) {
// do something
}
Source: sh step pipeline documentation

Is it possible to use pexpect to run another python script on switch?

Connecting to switch using expect spawn
child = pexpect.spawn('telnet ' + self.device_ip, timeout = 30)
When trying to run the below line, Im getting nothing as output
child.sendline('python script.py')
Can someone help me to run the python file over here?
I used
print("%s"%(child.before))
to print the output but it prints nothing
Make sure when you are using child.before that you have a child.expect statement beforehand. To put simply expect defines the text buffer that before references. Ex.
child = pexpect.spawn('telnet ' + self.device_ip, timeout = 30)
child.sendline('python script.py')
child.expect('user#abcd1234>')
remotehostoutput = (child.before)

Lua script unable to detect/catch error while executing invalid linux command

I have the following function that works fine as long as I give it a valid command to execute. As soon as I give it a non-existent command, the script is interrupted with an error message.
#!/usr/bin/lua
function exec_com(com)
local ok,res=pcall(function() return io.popen(com) end)
if ok then
local tmp=res:read('*a')
res:close()
return ok,tmp
else
return ok,res
end
end
local st,val=exec_com('uptime')
print('Executed "uptime" with status:'..tostring(st)..' and value:'..val)
st,val=exec_com('zzzz')
print('Executed "zzzz" with status:'..tostring(st)..' and value:'..val)
When I run the script above I get the following output:
Executed "uptime" with status:true and value: 18:07:38 up 1 day, 23:00, 3 users, load average: 0.37, 0.20, 0.20
sh: zzzz: command not found
Executed "zzzz" with status:true and value:
You can clearly see above that pcall() function still reported success when executing "zzzz" which is odd.
Can someone help me devise a way to catch an exception when executing a non-existent or ill-formed Linux command using Lua script? Thanks.
Edit: Restated my request after getting the clarification that pcall() works as expected, and the problem is due to popen() failing to throw an error.
I use a method which is similar to your "temporary workaround" but which gives you more information:
local cmd = "uptime"
local f = io.popen(cmd .. " 2>&1 || echo ::ERROR::", "r")
local text = f:read "*a"
if text:find "::ERROR::" then
-- something went wrong
print("error: " .. text)
else
-- all is fine!!
print(text)
end
If you look at io.popen(), you'll see that it'll always return a file handle.
Starts program prog in a separated process and returns a file handle
that you can use to read data from this program (if mode is "r", the
default) or to write data to this program (if mode is "w").
Since, a file handle returned is still a valid value for lua, the pcall(), your local function inside the pcall is returning a true value (and an error is not being propagated); thereby, giving you a true status and no output.
I have come up with my own temporary workaround that pipes the error to /dev/null and determines the success/failure of executed command based on the text received from io.popen():read('*a') command.
Here is my new code:
#!/usr/bin/lua
function exec_com(com)
local res=io.popen(com..' 2>/dev/null')
local tmp=res:read('*a')
res:close()
if string.len(tmp)>0 then
return true,tmp
else
return false,'Error executing command: '..com
end
end
local st,val=exec_com('uptime')
print('Executed "uptime" with status:'..tostring(st)..' and value:'..val)
st,val=exec_com('cat /etc/shadow')
print('Executed "cat /etc/shadow" with status:'..tostring(st)..' and value:'..val)
And the corresponding output is now correct:
Executed "uptime" with status:true and value: 00:10:11 up 2 days, 5:02, 3 users, load average: 0.01, 0.05, 0.19
Executed "cat /etc/shadow" with status:false and value:Error executing command: cat /etc/shadow
In my example above I am creating a "generic" error description. This is an intermediate fix and I am still interested in seeing alternative solutions that can return a more meaningful error message describing why the command failed to execute.
Rather than taking the time reading the whole file into a variable, why not just check if the file is empty with f:read(0)?
Local f = io.popen("NotExist")
if not f:read(0) Then
for l in st:lines() do
print(l)
end
else
error("Command Does Not Exist")
end
From the lua Manual:
As a special case, io.read(0) works as a test for end of file: It returns an empty string if there is more to be read or nil otherwise.

Resources