Merge lp:~ajkavanagh/charm-helpers/clean-up-render into lp:charm-helpers

Proposed by Alex Kavanagh
Status: Merged
Merged at revision: 782
Proposed branch: lp:~ajkavanagh/charm-helpers/clean-up-render
Merge into: lp:charm-helpers
Diff against target: 93 lines (+36/-8)
3 files modified
charmhelpers/contrib/openstack/templating.py (+5/-2)
charmhelpers/core/hookenv.py (+1/-0)
charmhelpers/core/host.py (+30/-6)
To merge this branch: bzr merge lp:~ajkavanagh/charm-helpers/clean-up-render
Reviewer Review Type Date Requested Status
David Ames (community) Approve
Review via email: mp+328859@code.launchpad.net

Description of the change

Update the core.host.write_file(...) function to do less work

The primary motivation for this change is to do less work, touch the
filesystem less, and try to clean the logs up a bit. This change is
to the rendering of configuration files, which generates noise in the
logs (at INFO) level, and often results in writing the exact same
content, thus updating the atime of the file even when the contents
haven't changed.

This change detects if the content will change, and if not, doesn't
write the file. It does detect if the uid,gid is changing and takes
the appropriate action. The logs are demoted to the lowest level of
DEBUG/TRACE, and are only generated IFF the file is actually written
or the uid/gid is changed.

To post a comment you must log in.
Revision history for this message
David Ames (thedac) wrote :

This looks good.

Before final approval I'd like to see it in one of our charms running an amulet full.

I realize this is a bit chicken and egg. But you can hijack the charm-helpers-hooks.yaml for this purpose.

Revision history for this message
David Ames (thedac) wrote :

Tests from the glance example pass.

Merging.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/contrib/openstack/templating.py'
--- charmhelpers/contrib/openstack/templating.py 2017-02-16 03:04:17 +0000
+++ charmhelpers/contrib/openstack/templating.py 2017-08-10 16:11:24 +0000
@@ -20,7 +20,8 @@
20from charmhelpers.core.hookenv import (20from charmhelpers.core.hookenv import (
21 log,21 log,
22 ERROR,22 ERROR,
23 INFO23 INFO,
24 TRACE
24)25)
25from charmhelpers.contrib.openstack.utils import OPENSTACK_CODENAMES26from charmhelpers.contrib.openstack.utils import OPENSTACK_CODENAMES
2627
@@ -80,8 +81,10 @@
80 loaders.insert(0, FileSystemLoader(tmpl_dir))81 loaders.insert(0, FileSystemLoader(tmpl_dir))
81 if rel == os_release:82 if rel == os_release:
82 break83 break
84 # demote this log to the lowest level; we don't really need to see these
85 # lots in production even when debugging.
83 log('Creating choice loader with dirs: %s' %86 log('Creating choice loader with dirs: %s' %
84 [l.searchpath for l in loaders], level=INFO)87 [l.searchpath for l in loaders], level=TRACE)
85 return ChoiceLoader(loaders)88 return ChoiceLoader(loaders)
8689
8790
8891
=== modified file 'charmhelpers/core/hookenv.py'
--- charmhelpers/core/hookenv.py 2017-08-01 10:53:23 +0000
+++ charmhelpers/core/hookenv.py 2017-08-10 16:11:24 +0000
@@ -43,6 +43,7 @@
43WARNING = "WARNING"43WARNING = "WARNING"
44INFO = "INFO"44INFO = "INFO"
45DEBUG = "DEBUG"45DEBUG = "DEBUG"
46TRACE = "TRACE"
46MARKER = object()47MARKER = object()
4748
48cache = {}49cache = {}
4950
=== modified file 'charmhelpers/core/host.py'
--- charmhelpers/core/host.py 2017-05-20 06:05:44 +0000
+++ charmhelpers/core/host.py 2017-08-10 16:11:24 +0000
@@ -34,7 +34,7 @@
3434
35from contextlib import contextmanager35from contextlib import contextmanager
36from collections import OrderedDict36from collections import OrderedDict
37from .hookenv import log37from .hookenv import log, DEBUG
38from .fstab import Fstab38from .fstab import Fstab
39from charmhelpers.osplatform import get_platform39from charmhelpers.osplatform import get_platform
4040
@@ -487,13 +487,37 @@
487487
488def write_file(path, content, owner='root', group='root', perms=0o444):488def write_file(path, content, owner='root', group='root', perms=0o444):
489 """Create or overwrite a file with the contents of a byte string."""489 """Create or overwrite a file with the contents of a byte string."""
490 log("Writing file {} {}:{} {:o}".format(path, owner, group, perms))
491 uid = pwd.getpwnam(owner).pw_uid490 uid = pwd.getpwnam(owner).pw_uid
492 gid = grp.getgrnam(group).gr_gid491 gid = grp.getgrnam(group).gr_gid
493 with open(path, 'wb') as target:492 # lets see if we can grab the file and compare the context, to avoid doing
494 os.fchown(target.fileno(), uid, gid)493 # a write.
495 os.fchmod(target.fileno(), perms)494 existing_content = None
496 target.write(content)495 existing_uid, existing_gid = None, None
496 try:
497 with open(path, 'rb') as target:
498 existing_content = target.read()
499 stat = os.stat(path)
500 existing_uid, existing_gid = stat.st_uid, stat.st_gid
501 except:
502 pass
503 if content != existing_content:
504 log("Writing file {} {}:{} {:o}".format(path, owner, group, perms),
505 level=DEBUG)
506 with open(path, 'wb') as target:
507 os.fchown(target.fileno(), uid, gid)
508 os.fchmod(target.fileno(), perms)
509 target.write(content)
510 return
511 # the contents were the same, but we might still need to change the
512 # ownership.
513 if existing_uid != uid:
514 log("Changing uid on already existing content: {} -> {}"
515 .format(existing_uid, uid), level=DEBUG)
516 os.chown(path, uid, -1)
517 if existing_gid != gid:
518 log("Changing gid on already existing content: {} -> {}"
519 .format(existing_gid, gid), level=DEBUG)
520 os.chown(path, -1, gid)
497521
498522
499def fstab_remove(mp):523def fstab_remove(mp):

Subscribers

People subscribed via source and target branches