Skip to content

Commit 6689726

Browse files
authored
Merge pull request #68 from vsoch/development
Development update for singularity 2.3
2 parents 1021e0f + 507cfa6 commit 6689726

File tree

7 files changed

+158
-66
lines changed

7 files changed

+158
-66
lines changed

singularity/build/google.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@
2727
2828
'''
2929

30-
from singularity.build.api import (
31-
api_get,
32-
api_put
33-
)
34-
3530
from singularity.build.utils import sniff_extension
3631

3732
from singularity.build.main import (
@@ -363,14 +358,13 @@ def get_build_metadata(key):
363358
'''
364359
headers = {"Metadata-Flavor":"Google"}
365360
url = "http://metadata.google.internal/computeMetadata/v1/instance/attributes/%s" %(key)
366-
response = api_get(url=url,headers=headers)
367-
361+
response = requests.get(url=url,headers=headers)
368362
# Successful query returns the result
369363
if response.status_code == 200:
370364
return response.text
371365
else:
372-
bot.logger.error("Error retrieving metadata %s, returned response %s", key,
373-
response.status_code)
366+
bot.logger.debug("Metadata %s not present, returned response %s", key,
367+
response.status_code)
374368
return None
375369

376370

singularity/build/scripts/singularity-build-latest.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ sudo apt-get -y install git \
55
build-essential \
66
libtool \
77
autotools-dev \
8+
debootstrap \
89
automake \
910
autoconf \
1011
python3-pip >> /tmp/.install-log

singularity/cli.py

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import tempfile
4545
import shutil
4646
import json
47+
import sys
4748
import os
4849
import re
4950

@@ -101,13 +102,41 @@ def help(self,command=None,stdout=True):
101102
return help
102103

103104

104-
def println(self,output):
105-
'''print will print the output, given that quiet is not True
105+
def println(self,output,quiet=False):
106+
'''print will print the output, given that quiet is not True. This
107+
function also serves to convert output in bytes to utf-8
106108
'''
107-
if self.quiet is False:
108-
if isinstance(output,bytes):
109-
output = output.decode('utf-8')
109+
if isinstance(output,bytes):
110+
output = output.decode('utf-8')
111+
112+
if self.quiet is False and quiet is False:
110113
print(output)
114+
return output
115+
116+
117+
def bootstrap(self,image_path,spec_path):
118+
'''create will bootstrap an image using a spec
119+
:param image_path: full path to image
120+
:param spec_path: full path to the spec file (Singularity)
121+
'''
122+
if self.debug == True:
123+
cmd = ['singularity','--debug','bootstrap',image_path,spec_path]
124+
else:
125+
cmd = ['singularity','bootstrap',image_path,spec_path]
126+
output = self.run_command(cmd,sudo=True)
127+
output = self.println(output)
128+
return image_path
129+
130+
131+
def compress(self,image_path):
132+
'''compress will (properly) compress an image'''
133+
if os.path.exists(image_path):
134+
compressed_image = "%s.gz" %image_path
135+
os.system('gzip -c -9 %s > %s' %(image_path,compressed_image))
136+
return compressed_image
137+
else:
138+
bot.logger.error("Cannot find image %s",image_path)
139+
return None
111140

112141

113142
def create(self,image_path,size=None,sudo=False):
@@ -124,24 +153,21 @@ def create(self,image_path,size=None,sudo=False):
124153
else:
125154
cmd = ['singularity','create','--size',str(size),image_path]
126155
output = self.run_command(cmd,sudo=sudo)
127-
self.println(output)
156+
output = self.println(output)
128157
if os.path.exists(image_path):
129158
return image_path
130159
return None
131160

132161

133-
def bootstrap(self,image_path,spec_path):
134-
'''create will bootstrap an image using a spec
135-
:param image_path: full path to image
136-
:param spec_path: full path to the spec file (Singularity)
137-
'''
138-
if self.debug == True:
139-
cmd = ['singularity','--debug','bootstrap',image_path,spec_path]
162+
163+
def decompress(self,image_path):
164+
'''decompress will (properly) decompress an image'''
165+
if os.path.exists(image_path):
166+
extracted_file = image_path.replace('.gz','')
167+
os.system('gzip -d -f %s' %image_path)
168+
return extracted_file
140169
else:
141-
cmd = ['singularity','bootstrap',image_path,spec_path]
142-
output = self.run_command(cmd,sudo=True)
143-
self.println(output)
144-
return image_path
170+
bot.logger.error("Cannot find image %s",image_path)
145171

146172

147173
def execute(self,image_path,command,writable=False,contain=False):
@@ -205,42 +231,78 @@ def importcmd(self,image_path,input_source):
205231
'''
206232
cmd = ['singularity','import',image_path,input_source]
207233
output = self.run_command(cmd,sudo=False)
208-
self.println(output)
234+
output = self.println(output)
209235
return image_path
210236

211237

212-
def pull(self,image_path,pull_folder=None,name_by=None):
238+
def inspect(self,image_path,json=True,labels=True,
239+
runscript=True,test=True,deffile=True,
240+
environment=True,quiet=False):
241+
'''inspect will show labels, defile, runscript, and tests for an image
242+
:param image_path: path of image to inspect
243+
:param json: print json instead of raw text (default True)
244+
:param labels: show labels (default True):
245+
:param runscript: show runscript (default True)
246+
:param test: show test file (default True)
247+
:param environment: show environment (default True)
248+
'''
249+
cmd = ['singularity','--quiet','inspect']
250+
options = locals()
251+
acceptable = ['environment','json','deffile','labels','runscript','test']
252+
for key,option in options.items():
253+
if key in acceptable:
254+
if option is True:
255+
cmd.append('--%s' %(key))
256+
257+
cmd.append(image_path)
258+
output = self.run_command(cmd)
259+
output = self.println(output,quiet=quiet)
260+
return output
261+
262+
263+
def pull(self,image_path,pull_folder=None,
264+
name_by_hash=False,
265+
name_by_commit=False,
266+
image_name=None):
213267
'''pull will pull a singularity hub image
214268
:param image_path: full path to image
215269
:param name_by: can be one of commit or hash, default is by image name
216270
'''
217-
if name_by is None:
218-
name_by = "name"
219-
name_by = name_by.lower()
271+
if image_name is not None:
272+
name_by_hash=False
273+
name_by_commit=False
220274

221275
if pull_folder is not None:
222276
os.environ['SINGULARITY_PULLFOLDER'] = pull_folder
223277

224-
if not image_path.startswith('shub://'):
225-
bot.logger.error("pull is only valid for the shub://uri, %s is invalid.",image_name)
278+
if not image_path.startswith('shub://') and not image_path.startswith('docker://'):
279+
bot.logger.error("pull is only valid for docker and shub, %s is invalid.",image_name)
226280
sys.exit(1)
227281

228282
if self.debug == True:
229283
cmd = ['singularity','--debug','pull']
230284
else:
231285
cmd = ['singularity','pull']
232286

233-
if name_by in ['name','commit','hash']:
234-
bot.logger.debug("user specified naming pulled image by %s",name_by)
235-
name_by = "--%s " %name_by
236-
cmd.append(name_by)
287+
if image_path.startswith('shub://'):
288+
if image_name is not None:
289+
bot.logger.debug("user specified naming pulled image %s",image_name)
290+
cmd = cmd +["--name",image_name]
291+
elif name_by_commit is True:
292+
bot.logger.debug("user specified naming by commit.")
293+
cmd.append("--commit")
294+
elif name_by_hash is True:
295+
bot.logger.debug("user specified naming by hash.")
296+
cmd.append("--hash")
297+
298+
elif image_path.startswith('docker://'):
299+
if image_name is not None:
300+
bot.logger.debug("user specified name of image as %s",image_name)
301+
cmd = cmd + ["--name",image_name]
237302

238303
cmd.append(image_path)
239-
240304
output = self.run_command(cmd)
241-
self.println(output)
242-
if isinstance(output,bytes):
243-
output = output.decode('utf-8')
305+
output = self.println(output,quiet=True)
244306
return output.split("Container is at:")[-1].strip('\n').strip()
245307

246308

@@ -266,8 +328,7 @@ def run(self,image_path,args=None,writable=False,contain=False):
266328
cmd = cmd + args
267329

268330
result = self.run_command(cmd,sudo=sudo)
269-
if isinstance(result,bytes):
270-
result = result.decode('utf-8')
331+
result = self.println(result,quiet=True)
271332
result = result.strip('\n')
272333
try:
273334
result = json.loads(result)
@@ -281,8 +342,7 @@ def get_labels(self,image_path):
281342
'''
282343
cmd = ['singularity','exec',image_path,'cat','/.singularity/labels.json']
283344
labels = self.run_command(cmd)
284-
if isinstance(labels,bytes):
285-
labels = labels.decode('utf-8')
345+
labels = self.println(labels,quiet=True)
286346
if len(labels) > 0:
287347
return json.loads(labels)
288348
return labels
@@ -302,13 +362,11 @@ def get_args(self,image_path):
302362
return args
303363

304364

305-
def add_flags(self,cmd,writable,contain):
365+
def add_flags(self,cmd,writable=False,contain=False):
306366
'''check_args is a general function for adding flags to a command list
307367
:param writable: adds --writable
308368
:param contain: adds --contain
309-
'''
310-
311-
# Does the user want to make the container writeable?
369+
'''
312370
if writable == True:
313371
cmd.append('--writable')
314372

singularity/hub/auth.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@
3333
import sys
3434

3535

36+
def basic_auth_header(username, password):
37+
'''basic_auth_header will return a base64 encoded header object to
38+
generate a token
39+
:param username: the username
40+
:param password: the password
41+
'''
42+
s = "%s:%s" % (username, password)
43+
if sys.version_info[0] >= 3:
44+
s = bytes(s, 'utf-8')
45+
credentials = base64.b64encode(s).decode('utf-8')
46+
else:
47+
credentials = base64.b64encode(s)
48+
auth = {"Authorization": "Basic %s" % credentials}
49+
return auth
50+
51+
52+
3653
def get_headers(token=None):
3754
'''get_headers will return a simple default header for a json
3855
post. This function will be adopted as needed.

singularity/package.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,6 @@ def package(image_path,spec_path=None,output_folder=None,runscript=True,
178178
if spec_path is not None:
179179
singularity_spec = "".join(read_file(spec_path))
180180
to_package['Singularity'] = singularity_spec
181-
182-
# Package the image with an sha1, identical standard, as VERSION
183-
if old_version == False:
184-
hashes = get_image_hashes(image_path)
185-
to_package["HASHES"] = hashes
186-
to_package["VERSION"] = hashes['IDENTICAL']
187-
else:
188181
to_package["VERSION"] = get_image_file_hash(image_path)
189182

190183

singularity/tests/test_client.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ def setUp(self):
4747
self.pwd = get_installdir()
4848
self.cli = Singularity()
4949
self.tmpdir = tempfile.mkdtemp()
50-
self.image1 = "%s/tests/data/busybox-2016-02-16.img" %(self.pwd)
51-
self.image2 = "%s/tests/data/cirros-2016-01-04.img" %(self.pwd)
5250

5351
def tearDown(self):
5452
shutil.rmtree(self.tmpdir)
@@ -75,37 +73,67 @@ def test_import(self):
7573
self.cli.importcmd(container,'docker://ubuntu')
7674
result = test_container(container)
7775
self.assertEqual(result['return_code'],0)
76+
os.remove(container)
7877

79-
def test_run(self):
80-
print("Testing client.run command")
78+
def test_exec(self):
79+
print('Testing client.execute command')
80+
container = create_container(do_import=True)
81+
result = self.cli.execute(container,'ls /')
82+
print(result)
83+
os.remove(container)
84+
#if isinstance(result,bytes):
85+
# result = result.decode('utf-8')
86+
#self.assertTrue(len(result)>0)
87+
88+
89+
def test_inspect(self):
90+
print("Testing client.inspect command")
8191
container = create_container(do_import=True)
82-
result = self.cli.run(container)
83-
self.assertEqual(result,'')
92+
result = self.cli.inspect(container,quiet=True)
93+
labels = json.loads(result)
94+
self.assertTrue('data' in labels)
95+
os.remove(container)
96+
8497

8598
def test_exec(self):
8699
print('Testing client.execute command')
87100
container = create_container(do_import=True)
88101
result = self.cli.execute(container,'ls /')
89102
print(result)
103+
os.remove(container)
104+
90105
#if isinstance(result,bytes):
91106
# result = result.decode('utf-8')
92107
#self.assertTrue(len(result)>0)
93108

94109

110+
95111
def test_pull(self):
96112
print("Testing client.pull command")
97113

98114
print("Case 1: Testing naming pull by image name")
99115
image = self.cli.pull("shub://vsoch/singularity-images")
116+
self.assertTrue(os.path.exists(image))
100117
print(image)
118+
os.remove(image)
101119

102120
print("Case 2: Testing naming pull by image commit")
103-
image = self.cli.pull("shub://vsoch/singularity-images",name_by="commit")
121+
image = self.cli.pull("shub://vsoch/singularity-images",name_by_commit=True)
122+
self.assertTrue(os.path.exists(image))
104123
print(image)
124+
os.remove(image)
105125

106126
print("Case 3: Testing naming pull by image hash")
107-
image = self.cli.pull("shub://vsoch/singularity-images",name_by="hash")
127+
image = self.cli.pull("shub://vsoch/singularity-images",name_by_hash=True)
128+
self.assertTrue(os.path.exists(image))
129+
print(image)
130+
os.remove(image)
131+
132+
print("Case 3: Testing docker pull")
133+
image = self.cli.pull("docker://ubuntu:14.04")
108134
print(image)
135+
self.assertTrue(os.path.exists(image))
136+
os.remove(image)
109137

110138

111139
def test_get_image(self):
@@ -125,9 +153,10 @@ def create_container(container=None,do_import=False):
125153
tmpdir = tempfile.mkdtemp()
126154
if container is None:
127155
container = "%s/container.img" %(tmpdir)
156+
container = cli.create(container)
128157
if do_import is True:
129158
cli.importcmd(container,'docker://ubuntu')
130-
return cli.create(container)
159+
return container
131160

132161

133162
if __name__ == '__main__':

singularity/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
SOFTWARE.
2323
'''
2424

25-
__version__ = "1.1.8"
25+
__version__ = "1.1.9"
2626
AUTHOR = 'Vanessa Sochat'
2727
AUTHOR_EMAIL = 'vsochat@stanford.edu'
2828
NAME = 'singularity'

0 commit comments

Comments
 (0)