Skip to content

Commit a75ed00

Browse files
committed
adding logs command
Signed-off-by: Vanessa Sochat <[email protected]>
1 parent 57c3c11 commit a75ed00

File tree

5 files changed

+110
-3
lines changed

5 files changed

+110
-3
lines changed

scompose/client/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,23 @@ def get_parser():
110110
kill = subparsers.add_parser("kill",
111111
help="kill instances")
112112

113+
# Logs
114+
113115
logs = subparsers.add_parser("logs",
114116
help="view output from instances")
115117

118+
logs.add_argument("--tail", default=0,
119+
dest='tail', type=int,
120+
help='clip logs to certain number of lines from end')
121+
116122
ps = subparsers.add_parser("ps",
117123
help="list instances")
118124

119125
restart = subparsers.add_parser("restart",
120126
help="stop and start containers.")
121127

122128
# Add list of names
123-
for sub in [create, down, up]:
129+
for sub in [create, down, logs, up]:
124130
sub.add_argument('names', nargs="*",
125131
help='the names of the instances to target')
126132

scompose/client/logs.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'''
2+
3+
Copyright (C) 2019 Vanessa Sochat.
4+
5+
This program is free software: you can redistribute it and/or modify it
6+
under the terms of the GNU Affero General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or (at your
8+
option) any later version.
9+
10+
This program is distributed in the hope that it will be useful, but WITHOUT
11+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
13+
License for more details.
14+
15+
You should have received a copy of the GNU Affero General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
'''
19+
20+
from scompose.project import Project
21+
import logging
22+
import json
23+
import sys
24+
import os
25+
26+
27+
log = logging.getLogger(__name__)
28+
29+
def main(args, parser, extra):
30+
'''bring one or more instances down
31+
'''
32+
# Initialize the project
33+
project = Project(filename=args.file,
34+
name=args.project_name,
35+
env_file=args.env_file)
36+
37+
# Create instances, and if none specified, create all
38+
project.logs(args.names, args.tail)

scompose/project/instance.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
'''
1919

2020
from scompose.logger import bot
21+
from scompose.utils import get_userhome
2122
from spython.main import get_client
2223
import shlex as _shlex
2324
import os
25+
import platform
2426
import sys
2527

2628

@@ -278,6 +280,46 @@ def stop(self):
278280
self.instance.stop(sudo=self.sudo)
279281
self.instance = None
280282

283+
# Logs
284+
285+
def logs(self, tail=0):
286+
'''show logs for an instance'''
287+
288+
home = get_userhome()
289+
user = os.path.basename(home)
290+
291+
if self.sudo:
292+
home = '/root'
293+
user = "root"
294+
295+
# Hostname
296+
hostname = platform.node()
297+
298+
log_folder = os.path.join(home, '.singularity', 'instances', 'logs', hostname, user)
299+
300+
for ext in ['OUT', 'ERR']:
301+
logfile = os.path.join(log_folder, '%s.%s' % (self.name, ext.lower()))
302+
303+
# Use Try/catch to account for not existing.
304+
try:
305+
if not self.sudo:
306+
result = self.client._run_command(['cat', logfile], quiet=True)
307+
else:
308+
result = self.client._run_command(['sudo', 'cat', logfile], quiet=True)
309+
310+
if result:
311+
312+
# If the user only wants to see certain number
313+
if tail > 0:
314+
result = '\n'.join(result.split('\n')[-tail:])
315+
bot.custom(prefix=self.name, message=ext, color='CYAN')
316+
print(result)
317+
bot.newline()
318+
319+
except:
320+
pass
321+
322+
281323
# Create and Delete
282324

283325
def up(self, working_dir, sudo=False, writable_tmpfs=False):

scompose/project/project.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,13 @@ def parse(self):
165165

166166
# Networking
167167

168-
169168
def create_hosts(self, name, depends_on):
170169
'''create a hosts file to bind to all containers, where we define the
171170
correct hostnames to correspond with the ip addresses created.
172171
173172
Note: This function is terrible. Singularity should easily expose
174-
these addresses.
173+
these addresses. See issue here:
174+
https://github.com/sylabs/singularity/issues/3751
175175
'''
176176
template = read_file(get_template('hosts'))
177177
hosts_file = os.path.join(self.working_dir, 'etc.hosts.%s' % name)
@@ -184,6 +184,7 @@ def create_hosts(self, name, depends_on):
184184
result = self.client.execute(image=instance.instance.get_uri(),
185185
command=['hostname', '-I'],
186186
return_result=True,
187+
quiet=True,
187188
sudo=self.sudo)
188189

189190
# Busybox won't have hostname -I
@@ -192,6 +193,7 @@ def create_hosts(self, name, depends_on):
192193
result = self.client.execute(image=instance.instance.get_uri(),
193194
command=cmd,
194195
return_result=True,
196+
quiet=True,
195197
sudo=self.sudo)
196198

197199
ip_address = result['message'].strip('\n').strip()
@@ -218,6 +220,19 @@ def shell(self, name):
218220
if instance.exists():
219221
self.client.shell(instance.instance.get_uri())
220222

223+
224+
def logs(self, names, tail=0):
225+
'''logs will print logs to the screen.
226+
'''
227+
# If no names provided, show all logs
228+
if not names:
229+
names = self.get_instance_names()
230+
231+
# Print logs for each
232+
for name in names:
233+
if name in self.instances:
234+
self.instances[name].logs(tail=tail)
235+
221236
# Config
222237

223238
def view_config(self):

scompose/utils/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ def get_installdir():
4040
return os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
4141

4242

43+
def get_userhome():
44+
'''get the user home based on the effective uid
45+
'''
46+
return pwd.getpwuid(os.getuid())[5]
47+
48+
4349
def run_command(cmd, sudo=False):
4450
'''run_command uses subprocess to send a command to the terminal.
4551

0 commit comments

Comments
 (0)