Skip to content

Commit

Permalink
Add the shadow map to the consul source
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilien Kenler committed Mar 21, 2017
1 parent 059e115 commit 0e00560
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 1 deletion.
45 changes: 44 additions & 1 deletion nss_cache/sources/consulsource.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from nss_cache.maps import group
from nss_cache.maps import passwd
from nss_cache.maps import shadow
from nss_cache.sources import httpsource


Expand Down Expand Up @@ -36,7 +37,7 @@ def _SetDefaults(self, configuration):
if 'datacenter' not in configuration:
configuration['datacenter'] = self.DATACENTER

for url in ['passwd_url', 'group_url']:
for url in ['passwd_url', 'group_url', 'shadow_url']:
configuration[url] = '{}?recurse&token={}&dc={}'.format(
configuration[url], configuration['token'], configuration['datacenter'])

Expand Down Expand Up @@ -64,6 +65,18 @@ def GetGroupMap(self, since=None):
"""
return GroupUpdateGetter().GetUpdates(self, self.conf['group_url'], since)

def GetShadowMap(self, since=None):
"""Return the shadow map from this source.
Args:
since: Get data only changed since this timestamp (inclusive) or None
for all data.
Returns:
instance of shadow.ShadowMap
"""
return ShadowUpdateGetter().GetUpdates(self, self.conf['shadow_url'], since)


class PasswdUpdateGetter(httpsource.UpdateGetter):
"""Get passwd updates."""
Expand All @@ -89,6 +102,17 @@ def CreateMap(self):
return group.GroupMap()


class ShadowUpdateGetter(httpsource.UpdateGetter):
"""Get shadow updates."""

def GetParser(self):
"""Returns a MapParser to parse FilesShadow cache."""
return ConsulShadowMapParser()

def CreateMap(self):
"""Returns a new ShadowMap instance to have ShadowMapEntries added to it."""
return shadow.ShadowMap()

class ConsulMapParser(object):
"""A base class for parsing nss_files module cache."""

Expand Down Expand Up @@ -174,3 +198,22 @@ def _ReadEntry(self, name, entry):
members = ['']
map_entry.members = members
return map_entry

class ConsulShadowMapParser(ConsulMapParser):
"""Class for parsing nss_files module shadow cache."""

def _ReadEntry(self, name, entry):
"""Return a ShadowMapEntry from a record in the target cache."""

map_entry = shadow.ShadowMapEntry()
# maps expect strict typing, so convert to int as appropriate.
map_entry.name = name
map_entry.passwd = entry.get('passwd', '*')

for attr in ['lstchg', 'min', 'max', 'warn', 'inact', 'expire']:
try:
setattr(map_entry, attr, int(entry[attr]))
except (ValueError, KeyError):
continue

return map_entry
36 changes: 36 additions & 0 deletions nss_cache/sources/consulsource_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from nss_cache.maps import group
from nss_cache.maps import passwd
from nss_cache.maps import shadow
from nss_cache.sources import consulsource


Expand Down Expand Up @@ -123,5 +124,40 @@ def testInvalidEntry(self):
self.assertEquals(entry, None)


class TestConsulShadowMapParser(unittest.TestCase):

def setUp(self):
self.good_entry = shadow.ShadowMapEntry()
self.good_entry.name = 'foo'
self.good_entry.passwd = '*'
self.good_entry.lstchg = 17246
self.good_entry.min = 0
self.good_entry.max = 99999
self.good_entry.warn = 7
self.parser = consulsource.ConsulShadowMapParser()

def testGetMap(self):
shadow_map = shadow.ShadowMap()
cache_info = StringIO.StringIO('''[
{"Key": "org/groups/foo/passwd", "Value": "Kg=="},
{"Key": "org/groups/foo/lstchg", "Value": "MTcyNDY="},
{"Key": "org/groups/foo/min", "Value": "MA=="},
{"Key": "org/groups/foo/max", "Value": "OTk5OTk="},
{"Key": "org/groups/foo/warn", "Value": "Nw=="}
]''')
self.parser.GetMap(cache_info, shadow_map)
self.assertEquals(self.good_entry, shadow_map.PopItem())

def testReadEntry(self):
data = {'passwd': '*', 'lstchg': 17246, 'min': 0, 'max': 99999, 'warn': 7}
entry = self.parser._ReadEntry('foo', data)
self.assertEquals(self.good_entry, entry)

def testDefaultPasswd(self):
data = {'lstchg': 17246, 'min': 0, 'max': 99999, 'warn': 7}
entry = self.parser._ReadEntry('foo', data)
self.assertEquals(self.good_entry, entry)


if __name__ == '__main__':
unittest.main()
2 changes: 2 additions & 0 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import logging
import os
import sys
import unittest


Expand All @@ -48,6 +49,7 @@

from nss_cache.sources.source_test import *
from nss_cache.sources.source_factory_test import *
from nss_cache.sources.consulsource_test import *
from nss_cache.sources.httpsource_test import *
from nss_cache.sources.ldapsource_test import *
# Unsupported and deprecated.
Expand Down

0 comments on commit 0e00560

Please sign in to comment.