Repository: deis/deis

Issue:
deis commands throw errors when being piped to head
When output of deis commands exceeds default number of lines `head` accepts (10), it starts throwing python exception. For example:

```
> $ deis logs -a staging -n 11 | head
2015-05-25T21:54:45UTC staging[web.1]:   Rendered shared/_head.html.slim (0.3ms)
2015-05-25T21:54:45UTC staging[web.1]:   Rendered shared/_ga.html.erb (0.2ms)
2015-05-26T08:56:36UTC staging[web.1]: Started GET "/" for 84.19.35.118 at 2015-05-26 08:56:36 +0000
2015-05-26T08:56:36UTC staging[web.1]: Processing by WebsiteController#index as HTML
2015-05-26T08:56:36UTC staging[web.1]: Filter chain halted as :authenticate rendered or redirected
2015-05-26T08:56:36UTC staging[web.1]: Completed 401 Unauthorized in 1ms
2015-05-26T22:06:34UTC staging[web.1]: Started GET "/" for 46.37.55.80 at 2015-05-26 22:06:34 +0000
2015-05-26T22:06:34UTC staging[web.1]: Processing by WebsiteController#index as HTML
2015-05-26T22:06:34UTC staging[web.1]: Filter chain halted as :authenticate rendered or redirected
2015-05-26T22:06:34UTC staging[web.1]: Completed 401 Unauthorized in 1ms
Traceback (most recent call last):
  File "/var/lib/jenkins/jobs/build-deis-cli-installer-linux/workspace/src/github.com/deis/deis/client/build/deis/out00-PYZ.pyz/logging", line 875, in emit
  File "/var/lib/jenkins/jobs/build-deis-cli-installer-linux/workspace/src/github.com/deis/deis/client/build/deis/out00-PYZ.pyz/logging", line 835, in flush
IOError: [Errno 32] Broken pipe
Logged from file <string>, line 670
```

but

```
> $ deis logs -a staging -n 10 | head
2015-05-25T21:54:45UTC staging[web.1]:   Rendered shared/_ga.html.erb (0.2ms)
2015-05-26T08:56:36UTC staging[web.1]: Started GET "/" for 84.19.35.118 at 2015-05-26 08:56:36 +0000
2015-05-26T08:56:36UTC staging[web.1]: Processing by WebsiteController#index as HTML
2015-05-26T08:56:36UTC staging[web.1]: Filter chain halted as :authenticate rendered or redirected
2015-05-26T08:56:36UTC staging[web.1]: Completed 401 Unauthorized in 1ms
2015-05-26T22:06:34UTC staging[web.1]: Started GET "/" for 46.37.55.80 at 2015-05-26 22:06:34 +0000
2015-05-26T22:06:34UTC staging[web.1]: Processing by WebsiteController#index as HTML
2015-05-26T22:06:34UTC staging[web.1]: Filter chain halted as :authenticate rendered or redirected
2015-05-26T22:06:34UTC staging[web.1]: Completed 401 Unauthorized in 1ms
2015-05-26T22:06:34UTC staging[web.1]: Started GET "/" for 46.37.55.80 at 2015-05-26 22:06:34 +0000
```

Exception output repeats for each line from 11.

This basically means that there is no way to extract first lines of output by `head -n 2`.



Discussion:
I can reproduce this, not sure yet what's causing it.

Probably related: http://stackoverflow.com/a/30091579/96855

TL;DR: If a sequence of commands appears in a pipeline, and one of the reading commands finishes before the writer has finished, the writer receives a SIGPIPE signal (for example `ps -aux | head`). Python itself by default traps SIGPIPE and throws IOError. Possible solution:

``` python
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
```


Resolving patch:
diff --git a/client/deis.py b/client/deis.py
--- a/client/deis.py
+++ b/client/deis.py
@@ -74,6 +74,11 @@
 from termcolor import colored
 import urllib3.contrib.pyopenssl
 
+# Don't throw IOError when a pipe closes
+# https://github.com/deis/deis/issues/3764
+from signal import signal, SIGPIPE, SIG_DFL
+signal(SIGPIPE, SIG_DFL)
+
 __version__ = '1.7.0-dev'
 
 # what version of the API is this client compatible with?


Test patch: