Commit fdfc1509 authored by Alain Takoudjou's avatar Alain Takoudjou

random-recipe: add option create-once to prevent storage file deletion by buildout

It sometimes happend that buildout unistall/install the section with this recipe,
which remore storage_path file and recreate it. In most of cases this is not wanted
because the recipe is used to generate password, so that password will change when this
happend.
To prevent buildout to remove storage_path, I introduced a new option 'create-once'
which, when set to True (the default value) will not let buildout play with storage_path file
by returning None in install recipe. Also install won't remove the file if the size is not 0.

/reviewed-on nexedi/slapos!129
parent 9f8227e7
...@@ -92,6 +92,9 @@ class Password(object): ...@@ -92,6 +92,9 @@ class Password(object):
- storage-path: plain-text persistent storage for password, - storage-path: plain-text persistent storage for password,
that can only be accessed by the user that can only be accessed by the user
(default: ${buildout:parts-directory}/${:_buildout_section_name_}) (default: ${buildout:parts-directory}/${:_buildout_section_name_})
- create-once: boolean value which set if storage-path won't be modified
as soon the file is created with the password (not empty).
(default: True)
If storage-path is empty, the recipe does not save the password, which is If storage-path is empty, the recipe does not save the password, which is
fine it is saved by other means, e.g. using the publish-early recipe. fine it is saved by other means, e.g. using the publish-early recipe.
...@@ -99,6 +102,8 @@ class Password(object): ...@@ -99,6 +102,8 @@ class Password(object):
def __init__(self, buildout, name, options): def __init__(self, buildout, name, options):
options_get = options.get options_get = options.get
self.create_once = options.get('create-once', 'True').lower() \
in GenericBaseRecipe.TRUE_VALUES
try: try:
self.storage_path = options['storage-path'] self.storage_path = options['storage-path']
except KeyError: except KeyError:
...@@ -112,9 +117,9 @@ class Password(object): ...@@ -112,9 +117,9 @@ class Password(object):
except IOError as e: except IOError as e:
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
raise raise
self.update = self.install
if not passwd: if not passwd:
passwd = self.generatePassword(int(options_get('bytes', '8'))) passwd = self.generatePassword(int(options_get('bytes', '8')))
self.update = self.install
self.passwd = passwd self.passwd = passwd
# Password must not go into .installed file, for 2 reasons: # Password must not go into .installed file, for 2 reasons:
# security of course but also to prevent buildout to always reinstall. # security of course but also to prevent buildout to always reinstall.
...@@ -126,17 +131,23 @@ class Password(object): ...@@ -126,17 +131,23 @@ class Password(object):
def install(self): def install(self):
if self.storage_path: if self.storage_path:
try: try:
# The following 2 lines are just an optimization to avoid recreating
# the file with the same content.
if self.create_once and os.stat(self.storage_path).st_size:
return
os.unlink(self.storage_path) os.unlink(self.storage_path)
except OSError as e: except OSError as e:
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
raise raise
fd = os.open(self.storage_path, fd = os.open(self.storage_path,
os.O_CREAT | os.O_EXCL | os.O_WRONLY | os.O_TRUNC, 0600) os.O_CREAT | os.O_EXCL | os.O_WRONLY | os.O_TRUNC, 0600)
try: try:
os.write(fd, self.passwd) os.write(fd, self.passwd)
finally: finally:
os.close(fd) os.close(fd)
return self.storage_path if not self.create_once:
return self.storage_path
def update(self): def update(self):
return () return ()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment