From 9b0bb227a963501d5db6e71a4bfd34809a585c87 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Tue, 22 Jul 2014 17:30:51 -0600 Subject: [PATCH] Added support for road estate role attribute in key identity Added tests --- salt/daemons/salting.py | 32 +- salt/daemons/test/test_saltkeep.py | 1456 +++++++++++++++++++++++++++- salt/key.py | 21 +- 3 files changed, 1470 insertions(+), 39 deletions(-) diff --git a/salt/daemons/salting.py b/salt/daemons/salting.py index 9be5c8d3de..fcfeb9a6cc 100644 --- a/salt/daemons/salting.py +++ b/salt/daemons/salting.py @@ -95,10 +95,10 @@ class SaltKeep(RoadKeep): ('joined', remote.joined), ('role', remote.role), ]) - if self.verifyRemoteData(data, remoteFields =self.RemoteDumpFields): + if self.verifyRemoteData(data, remoteFields=self.RemoteDumpFields): self.dumpRemoteData(data, remote.name) - self.saltRaetKey.status(remote.name, + self.saltRaetKey.status(remote.role, remote.uid, remote.pubber.keyhex, remote.verfer.keyhex) @@ -112,7 +112,7 @@ class SaltKeep(RoadKeep): if not data: return None - mid = remote.name + mid = remote.role statae = raeting.ACCEPTANCES.keys() for status in statae: keydata = self.saltRaetKey.read_remote(mid, status) @@ -132,16 +132,18 @@ class SaltKeep(RoadKeep): ''' Load and Return the data from the all the remote estate files ''' - data = super(SaltKeep, self).loadAllRemoteData() + keeps = super(SaltKeep, self).loadAllRemoteData() for status, mids in self.saltRaetKey.list_keys().items(): for mid in mids: keydata = self.saltRaetKey.read_remote(mid, status) - if keydata and data.get(mid): - data[mid].update(acceptance=raeting.ACCEPTANCES[status], + if keydata: + for name, data in keeps.items(): + if data['role'] == mid: + keeps[name].update(acceptance=raeting.ACCEPTANCES[status], verhex=keydata['verify'], pubhex=keydata['pub']) - return data + return keeps def clearAllRemoteData(self): ''' @@ -150,15 +152,15 @@ class SaltKeep(RoadKeep): super(SaltKeep, self).clearAllRemoteData() self.saltRaetKey.delete_all() - def replaceRemote(self, remote, old): + def replaceRemoteRole(self, remote, old): ''' - Replace the safe keep key file at old name given remote.name has changed - Assumes name uniqueness already taken care of + Replace the Salt RaetKey record at old role when remote.role has changed ''' - new = remote.name + new = remote.role if new != old: - self.dumpRemote(remote) #will be pending by default unless autoaccept + #self.dumpRemote(remote) # manually fix up acceptance if not pending + # will be pending by default unless autoaccept if remote.acceptance == raeting.acceptances.accepted: self.acceptRemote(remote) elif remote.acceptance == raeting.acceptances.rejected: @@ -171,7 +173,7 @@ class SaltKeep(RoadKeep): Evaluate acceptance status of remote estate per its keys persist key data differentially based on status ''' - status = raeting.ACCEPTANCES[self.saltRaetKey.status(remote.name, + status = raeting.ACCEPTANCES[self.saltRaetKey.status(remote.role, remote.eid, pubhex, verhex)] @@ -190,7 +192,7 @@ class SaltKeep(RoadKeep): Set acceptance status to rejected ''' remote.acceptance = raeting.acceptances.rejected - mid = remote.name + mid = remote.role self.saltRaetKey.reject(match=mid, include_accepted=True) def pendRemote(self, remote): @@ -204,7 +206,7 @@ class SaltKeep(RoadKeep): Set acceptance status to accepted ''' remote.acceptance = raeting.acceptances.accepted - mid = remote.name + mid = remote.role self.saltRaetKey.accept(match=mid, include_rejected=True) def clearAllKeep(dirpath): diff --git a/salt/daemons/test/test_saltkeep.py b/salt/daemons/test/test_saltkeep.py index b25a956bc8..adc74a9b40 100644 --- a/salt/daemons/test/test_saltkeep.py +++ b/salt/daemons/test/test_saltkeep.py @@ -43,6 +43,7 @@ class BasicTestCase(unittest.TestCase): self.timer = StoreTimer(store=self.store, duration=1.0) self.tempDirpath = tempfile.mkdtemp(prefix="salt", suffix='keep', dir='/tmp') + self.maxDiff = None def tearDown(self): if os.path.exists(self.tempDirpath): @@ -89,7 +90,7 @@ class BasicTestCase(unittest.TestCase): ) return opts - def createRoadData(self, name, cachedirpath): + def createRoadData(self, name, cachedirpath, role=None): ''' Creates odict and populates with data to setup road stack { @@ -110,6 +111,7 @@ class BasicTestCase(unittest.TestCase): privateer = nacling.Privateer() data['prihex'] = privateer.keyhex data['pubhex'] = privateer.pubhex + data['role'] = role or name return data @@ -130,7 +132,8 @@ class BasicTestCase(unittest.TestCase): name=data['name'], ha=ha, sigkey=data['sighex'], - prikey=data['prihex'],) + prikey=data['prihex'], + role=data['role']) stack = stacking.RoadStack(name=data['name'], local=local, @@ -182,10 +185,204 @@ class BasicTestCase(unittest.TestCase): def testBasic(self): ''' - Basic keep setup for stack keep and safe persistence load and dump + Basic keep setup for stack keep persistence load and dump in normal mode ''' console.terse("{0}\n".format(self.testBasic.__doc__)) + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + mainData = self.createRoadData(name='main', cachedirpath=opts['cachedir'] ) + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertFalse(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': False, + 'role': mainData['role'], + }) + + data1 = self.createRoadData(name='remote1', cachedirpath=opts['cachedir']) + main.addRemote(estating.RemoteEstate(stack=main, + eid=3, + name=data1['name'], + ha=('127.0.0.1', 7532), + verkey=data1['verhex'], + pubkey=data1['pubhex'], + period=main.period, + offset=main.offset, )) + + data2 = self.createRoadData(name='remote2', cachedirpath=opts['cachedir']) + main.addRemote(estating.RemoteEstate(stack=main, + eid=4, + name=data2['name'], + ha=('127.0.0.1', 7533), + verkey=data2['verhex'], + pubkey=data2['pubhex'], + period=main.period, + offset=main.offset,)) + + main.dumpRemotes() + + # acceptance will be pended + + self.assertDictEqual(main.keep.loadAllRemoteData(), + { + 'remote1': + {'uid': 3, + 'name': data1['name'], + 'ha': ['127.0.0.1', 7532], + 'sid': 0, + 'joined': None, + 'acceptance': 0, + 'verhex': data1['verhex'], + 'pubhex': data1['pubhex'], + 'role': data1['role'],}, + 'remote2': + {'uid': 4, + 'name': data2['name'], + 'ha': ['127.0.0.1', 7533], + 'sid': 0, + 'joined': None, + 'acceptance': 0, + 'verhex': data2['verhex'], + 'pubhex': data2['pubhex'], + 'role': data2['role'],} + }) + + # now recreate with saved data + main.server.close() + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + main = stacking.RoadStack(name=mainData['name'], + store=self.store, + keep=mainKeep) + + self.assertEqual(main.local.priver.keyhex, mainData['prihex']) + self.assertEqual(main.local.signer.keyhex, mainData['sighex']) + + self.assertEqual(len(main.remotes.values()), 2) + + # other stack + opts = self.createOpts(name='other', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + otherData = self.createRoadData(name='other', cachedirpath=opts['cachedir'] ) + otherKeep = salting.SaltKeep(opts=opts, + basedirpath=otherData['basedirpath'], + stackname=otherData['name']) + + self.assertEqual(otherKeep.loadLocalData(), None) + self.assertEqual(otherKeep.loadAllRemoteData(), {}) + + other = self.createRoadStack(data=otherData, + eid=0, + main=None, + ha=("", raeting.RAET_TEST_PORT), + keep=otherKeep) + + console.terse("{0} keep dirpath = {1}\n".format( + other.name, other.keep.dirpath)) + self.assertTrue(other.keep.dirpath.endswith('other/raet/other')) + self.assertEqual(other.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertFalse(other.keep.auto) + + self.assertDictEqual(other.keep.loadLocalData(), + { + 'uid': 0, + 'name': otherData['name'], + 'ha': ['0.0.0.0', 7531], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': otherData['sighex'], + 'prihex': otherData['prihex'], + 'auto': False, + 'role': otherData['role'], + }) + + data3 = self.createRoadData(name='remote3', cachedirpath=opts['cachedir']) + other.addRemote(estating.RemoteEstate(stack=other, + eid=3, + name=data3['name'], + ha=('127.0.0.1', 7534), + verkey=data3['verhex'], + pubkey=data3['pubhex'], + period=main.period, + offset=main.offset,)) + + data4 = self.createRoadData(name='remote4', cachedirpath=opts['cachedir']) + other.addRemote(estating.RemoteEstate(stack=other, + eid=4, + name=data4['name'], + ha=('127.0.0.1', 7535), + verkey=data4['verhex'], + pubkey=data4['pubhex'], + period=main.period, + offset=main.offset,)) + + other.dumpRemotes() + self.assertDictEqual(other.keep.loadAllRemoteData(), + { + 'remote3': + { + 'uid': 3, + 'name': data3['name'], + 'ha': ['127.0.0.1', 7534], + 'sid': 0, + 'joined': None, + 'acceptance': 0, + 'verhex': data3['verhex'], + 'pubhex': data3['pubhex'], + 'role': data3['role'], + }, + 'remote4': + { + 'uid': 4, + 'name': data4['name'], + 'ha': ['127.0.0.1', 7535], + 'sid': 0, + 'joined': None, + 'acceptance': 0, + 'verhex': data4['verhex'], + 'pubhex': data4['pubhex'], + 'role': data4['role'], + } + }) + + main.server.close() + other.server.close() + + def testBasicOpen(self): + ''' + Basic keep setup for stack keep persistence load and dump in open mode + ''' + console.terse("{0}\n".format(self.testBasicOpen.__doc__)) + opts = self.createOpts(name='main', dirpath=self.tempDirpath, openMode=True, @@ -218,7 +415,7 @@ class BasicTestCase(unittest.TestCase): 'sighex': mainData['sighex'], 'prihex': mainData['prihex'], 'auto': True, - 'role': mainData['name'], + 'role': mainData['role'], }) data1 = self.createRoadData(name='remote1', cachedirpath=opts['cachedir']) @@ -254,7 +451,7 @@ class BasicTestCase(unittest.TestCase): 'acceptance': 1, 'verhex': data1['verhex'], 'pubhex': data1['pubhex'], - 'role': data1['name'],}, + 'role': data1['role'],}, 'remote2': {'uid': 4, 'name': data2['name'], @@ -264,7 +461,7 @@ class BasicTestCase(unittest.TestCase): 'acceptance': 1, 'verhex': data2['verhex'], 'pubhex': data2['pubhex'], - 'role': data2['name'],} + 'role': data2['role'],} }) # now recreate with saved data @@ -304,6 +501,7 @@ class BasicTestCase(unittest.TestCase): other.name, other.keep.dirpath)) self.assertTrue(other.keep.dirpath.endswith('other/raet/other')) self.assertEqual(other.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertTrue(other.keep.auto) self.assertDictEqual(other.keep.loadLocalData(), { @@ -316,7 +514,7 @@ class BasicTestCase(unittest.TestCase): 'sighex': otherData['sighex'], 'prihex': otherData['prihex'], 'auto': True, - 'role': otherData['name'], + 'role': otherData['role'], }) data3 = self.createRoadData(name='remote3', cachedirpath=opts['cachedir']) @@ -352,7 +550,7 @@ class BasicTestCase(unittest.TestCase): 'acceptance': 1, 'verhex': data3['verhex'], 'pubhex': data3['pubhex'], - 'role': data3['name'], + 'role': data3['role'], }, 'remote4': { @@ -364,19 +562,705 @@ class BasicTestCase(unittest.TestCase): 'acceptance': 1, 'verhex': data4['verhex'], 'pubhex': data4['pubhex'], - 'role': data4['name'], + 'role': data4['role'], } }) main.server.close() other.server.close() + def testBasicAuto(self): + ''' + Basic keep setup for stack keep persistence load and dump with auto accept + ''' + console.terse("{0}\n".format(self.testBasicAuto.__doc__)) + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + mainData = self.createRoadData(name='main', cachedirpath=opts['cachedir'] ) + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertTrue(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': True, + 'role': mainData['role'], + }) + + data1 = self.createRoadData(name='remote1', cachedirpath=opts['cachedir']) + main.addRemote(estating.RemoteEstate(stack=main, + eid=3, + name=data1['name'], + ha=('127.0.0.1', 7532), + verkey=data1['verhex'], + pubkey=data1['pubhex'], + period=main.period, + offset=main.offset, )) + + data2 = self.createRoadData(name='remote2', cachedirpath=opts['cachedir']) + main.addRemote(estating.RemoteEstate(stack=main, + eid=4, + name=data2['name'], + ha=('127.0.0.1', 7533), + verkey=data2['verhex'], + pubkey=data2['pubhex'], + period=main.period, + offset=main.offset,)) + + main.dumpRemotes() + + self.assertDictEqual(main.keep.loadAllRemoteData(), + { + 'remote1': + {'uid': 3, + 'name': data1['name'], + 'ha': ['127.0.0.1', 7532], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data1['verhex'], + 'pubhex': data1['pubhex'], + 'role': data1['role'],}, + 'remote2': + {'uid': 4, + 'name': data2['name'], + 'ha': ['127.0.0.1', 7533], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data2['verhex'], + 'pubhex': data2['pubhex'], + 'role': data2['role'],} + }) + + # now recreate with saved data + main.server.close() + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + main = stacking.RoadStack(name=mainData['name'], + store=self.store, + keep=mainKeep) + + self.assertEqual(main.local.priver.keyhex, mainData['prihex']) + self.assertEqual(main.local.signer.keyhex, mainData['sighex']) + + self.assertEqual(len(main.remotes.values()), 2) + + # other stack + opts = self.createOpts(name='other', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + otherData = self.createRoadData(name='other', cachedirpath=opts['cachedir'] ) + otherKeep = salting.SaltKeep(opts=opts, + basedirpath=otherData['basedirpath'], + stackname=otherData['name']) + + self.assertEqual(otherKeep.loadLocalData(), None) + self.assertEqual(otherKeep.loadAllRemoteData(), {}) + + other = self.createRoadStack(data=otherData, + eid=0, + main=None, + ha=("", raeting.RAET_TEST_PORT), + keep=otherKeep) + + console.terse("{0} keep dirpath = {1}\n".format( + other.name, other.keep.dirpath)) + self.assertTrue(other.keep.dirpath.endswith('other/raet/other')) + self.assertEqual(other.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertTrue(other.keep.auto) + + self.assertDictEqual(other.keep.loadLocalData(), + { + 'uid': 0, + 'name': otherData['name'], + 'ha': ['0.0.0.0', 7531], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': otherData['sighex'], + 'prihex': otherData['prihex'], + 'auto': True, + 'role': otherData['role'], + }) + + data3 = self.createRoadData(name='remote3', cachedirpath=opts['cachedir']) + other.addRemote(estating.RemoteEstate(stack=other, + eid=3, + name=data3['name'], + ha=('127.0.0.1', 7534), + verkey=data3['verhex'], + pubkey=data3['pubhex'], + period=main.period, + offset=main.offset,)) + + data4 = self.createRoadData(name='remote4', cachedirpath=opts['cachedir']) + other.addRemote(estating.RemoteEstate(stack=other, + eid=4, + name=data4['name'], + ha=('127.0.0.1', 7535), + verkey=data4['verhex'], + pubkey=data4['pubhex'], + period=main.period, + offset=main.offset,)) + + other.dumpRemotes() + self.assertDictEqual(other.keep.loadAllRemoteData(), + { + 'remote3': + { + 'uid': 3, + 'name': data3['name'], + 'ha': ['127.0.0.1', 7534], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data3['verhex'], + 'pubhex': data3['pubhex'], + 'role': data3['role'], + }, + 'remote4': + { + 'uid': 4, + 'name': data4['name'], + 'ha': ['127.0.0.1', 7535], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data4['verhex'], + 'pubhex': data4['pubhex'], + 'role': data4['role'], + } + }) + + main.server.close() + other.server.close() + + def testBasicRole(self): + ''' + Basic keep setup for stack keep persistence load and dump with shared role + ''' + console.terse("{0}\n".format(self.testBasicRole.__doc__)) + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + mainData = self.createRoadData(name='main', + cachedirpath=opts['cachedir'], + role='serious') + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertFalse(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': False, + 'role': mainData['role'], + }) + + # add multiple remotes all with same role + data1 = self.createRoadData(name='remote1', + cachedirpath=opts['cachedir'], + role='primary') + main.addRemote(estating.RemoteEstate(stack=main, + eid=3, + name=data1['name'], + ha=('127.0.0.1', 7532), + verkey=data1['verhex'], + pubkey=data1['pubhex'], + period=main.period, + offset=main.offset, + role=data1['role']) ) + + data2 = self.createRoadData(name='remote2', + cachedirpath=opts['cachedir'], + role='primary') + main.addRemote(estating.RemoteEstate(stack=main, + eid=4, + name=data2['name'], + ha=('127.0.0.1', 7533), + verkey=data2['verhex'], + pubkey=data2['pubhex'], + period=main.period, + offset=main.offset, + role=data2['role']) ) + + main.dumpRemotes() + + # will save remote1 keys and reuse for remote2 + + self.assertDictEqual(main.keep.loadAllRemoteData(), + { + 'remote1': + {'uid': 3, + 'name': data1['name'], + 'ha': ['127.0.0.1', 7532], + 'sid': 0, + 'joined': None, + 'acceptance': 0, + 'verhex': data1['verhex'], + 'pubhex': data1['pubhex'], + 'role': data1['role'],}, + 'remote2': + {'uid': 4, + 'name': data2['name'], + 'ha': ['127.0.0.1', 7533], + 'sid': 0, + 'joined': None, + 'acceptance': 0, + 'verhex': data1['verhex'], + 'pubhex': data1['pubhex'], + 'role': data2['role'],} + }) + + # now recreate with saved data + main.server.close() + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + main = stacking.RoadStack(name=mainData['name'], + store=self.store, + keep=mainKeep) + + self.assertEqual(main.local.name, mainData['name']) + self.assertEqual(main.local.uid, 1) + self.assertEqual(main.local.main, True) + self.assertEqual(main.local.role, mainData['role']) + self.assertFalse(main.keep.auto) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertEqual(main.local.priver.keyhex, mainData['prihex']) + self.assertEqual(main.local.signer.keyhex, mainData['sighex']) + + self.assertEqual(len(main.remotes.values()), 2) + for data in [data1, data2]: + remote = main.nameRemotes[data['name']] + self.assertEqual(remote.name, data['name']) + self.assertEqual(remote.role, data['role']) + self.assertEqual(remote.pubber.keyhex, data1['pubhex']) + self.assertEqual(remote.verfer.keyhex, data1['verhex']) + + main.server.close() + + def testBasicRoleOpen(self): + ''' + Basic keep setup for stack keep persistence load and dump with shared role + ''' + console.terse("{0}\n".format(self.testBasicRoleOpen.__doc__)) + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=True, + autoAccept=True) + mainData = self.createRoadData(name='main', + cachedirpath=opts['cachedir'], + role='serious') + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertTrue(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': True, + 'role': mainData['role'], + }) + + # add multiple remotes all with same role + data1 = self.createRoadData(name='remote1', + cachedirpath=opts['cachedir'], + role='primary') + main.addRemote(estating.RemoteEstate(stack=main, + eid=3, + name=data1['name'], + ha=('127.0.0.1', 7532), + verkey=data1['verhex'], + pubkey=data1['pubhex'], + period=main.period, + offset=main.offset, + role=data1['role']) ) + + data2 = self.createRoadData(name='remote2', + cachedirpath=opts['cachedir'], + role='primary') + main.addRemote(estating.RemoteEstate(stack=main, + eid=4, + name=data2['name'], + ha=('127.0.0.1', 7533), + verkey=data2['verhex'], + pubkey=data2['pubhex'], + period=main.period, + offset=main.offset, + role=data2['role']) ) + + main.dumpRemotes() + + self.assertDictEqual(main.keep.loadAllRemoteData(), + { + 'remote1': + {'uid': 3, + 'name': data1['name'], + 'ha': ['127.0.0.1', 7532], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data2['verhex'], + 'pubhex': data2['pubhex'], + 'role': data1['role'],}, + 'remote2': + {'uid': 4, + 'name': data2['name'], + 'ha': ['127.0.0.1', 7533], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data2['verhex'], + 'pubhex': data2['pubhex'], + 'role': data2['role'],} + }) + + # now recreate with saved data + main.server.close() + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + main = stacking.RoadStack(name=mainData['name'], + store=self.store, + keep=mainKeep) + + self.assertEqual(main.local.name, mainData['name']) + self.assertEqual(main.local.uid, 1) + self.assertEqual(main.local.main, True) + self.assertEqual(main.local.role, mainData['role']) + self.assertTrue(main.keep.auto) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertEqual(main.local.priver.keyhex, mainData['prihex']) + self.assertEqual(main.local.signer.keyhex, mainData['sighex']) + + self.assertEqual(len(main.remotes.values()), 2) + for data in [data1, data2]: + remote = main.nameRemotes[data['name']] + self.assertEqual(remote.name, data['name']) + self.assertEqual(remote.role, data['role']) + self.assertEqual(remote.pubber.keyhex, data2['pubhex']) + self.assertEqual(remote.verfer.keyhex, data2['verhex']) + + main.server.close() + + def testBasicRoleAuto(self): + ''' + Basic keep setup for stack keep persistence load and dump with shared role + ''' + console.terse("{0}\n".format(self.testBasicRoleAuto.__doc__)) + self.maxDiff = None + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + mainData = self.createRoadData(name='main', + cachedirpath=opts['cachedir'], + role='serious') + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertTrue(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': True, + 'role': mainData['role'], + }) + + # add multiple remotes all with same role + data1 = self.createRoadData(name='remote1', + cachedirpath=opts['cachedir'], + role='primary') + main.addRemote(estating.RemoteEstate(stack=main, + eid=3, + name=data1['name'], + ha=('127.0.0.1', 7532), + verkey=data1['verhex'], + pubkey=data1['pubhex'], + period=main.period, + offset=main.offset, + role=data1['role']) ) + + data2 = self.createRoadData(name='remote2', + cachedirpath=opts['cachedir'], + role='primary') + main.addRemote(estating.RemoteEstate(stack=main, + eid=4, + name=data2['name'], + ha=('127.0.0.1', 7533), + verkey=data2['verhex'], + pubkey=data2['pubhex'], + period=main.period, + offset=main.offset, + role=data2['role']) ) + + main.dumpRemotes() + + # remote2 keys will be rejected since keys do not match remote1 but same role + # upon reloading the keys for remote2 will be those from remote1 + + self.assertDictEqual(main.keep.loadAllRemoteData(), + { + 'remote1': + {'uid': 3, + 'name': data1['name'], + 'ha': ['127.0.0.1', 7532], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data1['verhex'], + 'pubhex': data1['pubhex'], + 'role': data1['role'],}, + 'remote2': + {'uid': 4, + 'name': data2['name'], + 'ha': ['127.0.0.1', 7533], + 'sid': 0, + 'joined': None, + 'acceptance': 1, + 'verhex': data1['verhex'], + 'pubhex': data1['pubhex'], + 'role': data2['role'],} + }) + + # now recreate with saved data + main.server.close() + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + main = stacking.RoadStack(name=mainData['name'], + store=self.store, + keep=mainKeep) + + self.assertEqual(main.local.name, mainData['name']) + self.assertEqual(main.local.uid, 1) + self.assertEqual(main.local.main, True) + self.assertEqual(main.local.role, mainData['role']) + self.assertTrue(main.keep.auto) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertEqual(main.local.priver.keyhex, mainData['prihex']) + self.assertEqual(main.local.signer.keyhex, mainData['sighex']) + + self.assertEqual(len(main.remotes.values()), 2) + for data in [data1, data2]: + remote = main.nameRemotes[data['name']] + self.assertEqual(remote.name, data['name']) + self.assertEqual(remote.role, data['role']) + self.assertEqual(remote.acceptance, 1) + self.assertEqual(remote.pubber.keyhex, data1['pubhex']) + self.assertEqual(remote.verfer.keyhex, data1['verhex']) + + + main.server.close() + def testBootstrapClean(self): ''' Bootstap to allowed ''' console.terse("{0}\n".format(self.testBootstrapClean.__doc__)) + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + mainData = self.createRoadData(name='main', cachedirpath=opts['cachedir'] ) + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertFalse(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': False, + 'role': mainData['role'], + }) + + opts = self.createOpts(name='other', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + otherData = self.createRoadData(name='other', cachedirpath=opts['cachedir'] ) + otherKeep = salting.SaltKeep(opts=opts, + basedirpath=otherData['basedirpath'], + stackname=otherData['name']) + + self.assertEqual(otherKeep.loadLocalData(), None) + self.assertEqual(otherKeep.loadAllRemoteData(), {}) + + other = self.createRoadStack(data=otherData, + eid=0, + main=None, + ha=("", raeting.RAET_TEST_PORT), + keep=otherKeep) + + console.terse("{0} keep dirpath = {1}\n".format( + other.name, other.keep.dirpath)) + self.assertTrue(other.keep.dirpath.endswith('other/raet/other')) + self.assertEqual(other.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertFalse(other.keep.auto) + self.assertDictEqual(other.keep.loadLocalData(), + { + 'uid': 0, + 'name': otherData['name'], + 'ha': ['0.0.0.0', 7531], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': otherData['sighex'], + 'prihex': otherData['prihex'], + 'auto': False, + 'role': otherData['role'], + }) + + self.join(other, main) + self.assertEqual(len(main.transactions), 1) # pending + main.keep.acceptRemote(main.nameRemotes[other.local.name]) + self.service(main, other, duration=1.0) + + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.joined) + self.assertEqual(len(other.transactions), 0) + remote = other.remotes.values()[0] + self.assertTrue(remote.joined) + + self.allow(other, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.allowed) + self.assertEqual(len(other.transactions), 0) + remote = other.remotes.values()[0] + self.assertTrue(remote.allowed) + + for remote in main.remotes.values(): + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertTrue(os.path.exists(path)) + + + # now delete a key and see if road keep file is also deleted + main.keep.saltRaetKey.delete_key(match=other.local.role) + remote = main.remotes[other.local.uid] + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + + main.server.close() + other.server.close() + + def testBootstrapOpen(self): + ''' + Bootstap to allowed + ''' + console.terse("{0}\n".format(self.testBootstrapOpen.__doc__)) + opts = self.createOpts(name='main', dirpath=self.tempDirpath, openMode=True, @@ -409,7 +1293,7 @@ class BasicTestCase(unittest.TestCase): 'sighex': mainData['sighex'], 'prihex': mainData['prihex'], 'auto': True, - 'role': mainData['name'], + 'role': mainData['role'], }) opts = self.createOpts(name='other', @@ -424,6 +1308,116 @@ class BasicTestCase(unittest.TestCase): self.assertEqual(otherKeep.loadLocalData(), None) self.assertEqual(otherKeep.loadAllRemoteData(), {}) + other = self.createRoadStack(data=otherData, + eid=0, + main=None, + ha=("", raeting.RAET_TEST_PORT), + keep=otherKeep) + + console.terse("{0} keep dirpath = {1}\n".format( + other.name, other.keep.dirpath)) + self.assertTrue(other.keep.dirpath.endswith('other/raet/other')) + self.assertEqual(other.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertTrue(other.keep.auto) + self.assertDictEqual(other.keep.loadLocalData(), + { + 'uid': 0, + 'name': otherData['name'], + 'ha': ['0.0.0.0', 7531], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': otherData['sighex'], + 'prihex': otherData['prihex'], + 'auto': True, + 'role': otherData['role'], + }) + + self.join(other, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.joined) + self.assertEqual(len(other.transactions), 0) + remote = other.remotes.values()[0] + self.assertTrue(remote.joined) + + self.allow(other, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.allowed) + self.assertEqual(len(other.transactions), 0) + remote = other.remotes.values()[0] + self.assertTrue(remote.allowed) + + for remote in main.remotes.values(): + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertTrue(os.path.exists(path)) + + + # now delete a key and see if road keep file is also deleted + main.keep.saltRaetKey.delete_key(match=other.local.role) + remote = main.remotes[other.local.uid] + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + + main.server.close() + other.server.close() + + def testBootstrapAuto(self): + ''' + Bootstap to allowed + ''' + console.terse("{0}\n".format(self.testBootstrapAuto.__doc__)) + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + mainData = self.createRoadData(name='main', cachedirpath=opts['cachedir'] ) + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertTrue(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': True, + 'role': mainData['role'], + }) + + opts = self.createOpts(name='other', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + otherData = self.createRoadData(name='other', cachedirpath=opts['cachedir'] ) + otherKeep = salting.SaltKeep(opts=opts, + basedirpath=otherData['basedirpath'], + stackname=otherData['name']) + + self.assertEqual(otherKeep.loadLocalData(), None) + self.assertEqual(otherKeep.loadAllRemoteData(), {}) + other = self.createRoadStack(data=otherData, eid=0, main=None, @@ -445,7 +1439,7 @@ class BasicTestCase(unittest.TestCase): 'sighex': otherData['sighex'], 'prihex': otherData['prihex'], 'auto': True, - 'role': otherData['name'], + 'role': otherData['role'], }) self.join(other, main) @@ -471,7 +1465,7 @@ class BasicTestCase(unittest.TestCase): # now delete a key and see if road keep file is also deleted - main.keep.saltRaetKey.delete_key(match=other.local.name) + main.keep.saltRaetKey.delete_key(match=other.local.role) remote = main.remotes[other.local.uid] path = os.path.join(main.keep.remotedirpath, "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) @@ -480,6 +1474,430 @@ class BasicTestCase(unittest.TestCase): main.server.close() other.server.close() + def testBootstrapRole(self): + ''' + Bootstap to allowed with multiple remotes using same role + ''' + console.terse("{0}\n".format(self.testBootstrapRole.__doc__)) + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + mainData = self.createRoadData(name='main', cachedirpath=opts['cachedir'] ) + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertFalse(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': False, + 'role': mainData['role'], + }) + + opts = self.createOpts(name='other1', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + other1Data = self.createRoadData(name='other1', + cachedirpath=opts['cachedir'], + role='primary') + other1Keep = salting.SaltKeep(opts=opts, + basedirpath=other1Data['basedirpath'], + stackname=other1Data['name']) + + self.assertEqual(other1Keep.loadLocalData(), None) + self.assertEqual(other1Keep.loadAllRemoteData(), {}) + + other1 = self.createRoadStack(data=other1Data, + eid=0, + main=None, + ha=("", raeting.RAET_TEST_PORT), + keep=other1Keep) + + console.terse("{0} keep dirpath = {1}\n".format( + other1.name, other1.keep.dirpath)) + self.assertTrue(other1.keep.dirpath.endswith('other1/raet/other1')) + self.assertEqual(other1.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertFalse(other1.keep.auto) + self.assertDictEqual(other1.keep.loadLocalData(), + { + 'uid': 0, + 'name': other1Data['name'], + 'ha': ['0.0.0.0', 7531], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': other1Data['sighex'], + 'prihex': other1Data['prihex'], + 'auto': False, + 'role': other1Data['role'], + }) + + self.join(other1, main) + self.assertEqual(len(main.transactions), 1) # pending + main.keep.acceptRemote(main.nameRemotes[other1.local.name]) + self.service(main, other1, duration=1.0) + + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.joined) + self.assertEqual(len(other1.transactions), 0) + remote = other1.remotes.values()[0] + self.assertTrue(remote.joined) + + self.allow(other1, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.allowed) + self.assertEqual(len(other1.transactions), 0) + remote = other1.remotes.values()[0] + self.assertTrue(remote.allowed) + + for remote in main.remotes.values(): + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertTrue(os.path.exists(path)) + + # create other2 stack but use same role but different keys as other1 + opts = self.createOpts(name='other2', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + other2Data = self.createRoadData(name='other2', + cachedirpath=opts['cachedir'], + role='primary') + other2Keep = salting.SaltKeep(opts=opts, + basedirpath=other2Data['basedirpath'], + stackname=other2Data['name']) + + self.assertEqual(other2Keep.loadLocalData(), None) + self.assertEqual(other2Keep.loadAllRemoteData(), {}) + + other2 = self.createRoadStack(data=other2Data, + eid=0, + main=None, + ha=("", 7532), + keep=other2Keep) + + console.terse("{0} keep dirpath = {1}\n".format( + other2.name, other2.keep.dirpath)) + self.assertTrue(other2.keep.dirpath.endswith('other2/raet/other2')) + self.assertEqual(other2.local.ha, ("0.0.0.0", 7532)) + self.assertFalse(other2.keep.auto) + self.assertDictEqual(other2.keep.loadLocalData(), + { + 'uid': 0, + 'name': other2Data['name'], + 'ha': ['0.0.0.0', 7532], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': other2Data['sighex'], + 'prihex': other2Data['prihex'], + 'auto': False, + 'role': other2Data['role'], + }) + + # should not join since role same but keys different + self.join(other2, main) + self.assertEqual(len(main.transactions), 0) # rejected since not same keys + self.assertEqual(other2.remotes.values()[0].joined, False) + self.assertEqual(len(main.remotes), 2) + main.removeRemote(main.nameRemotes[other2.local.name], clear=True) + other2.server.close() + other2.keep.clearAllDir() + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, other2.local.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + shutil.rmtree(opts['pki_dir']) + + + + # recreate other2 stack but use same role and same keys as other1 + opts = self.createOpts(name='other2', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + other2Data = self.createRoadData(name='other2', + cachedirpath=opts['cachedir'], + role='primary') + other2Data['sighex'] = other1Data['sighex'] + other2Data['prihex'] = other1Data['prihex'] + other2Keep = salting.SaltKeep(opts=opts, + basedirpath=other2Data['basedirpath'], + stackname=other2Data['name']) + + self.assertEqual(other2Keep.loadLocalData(), None) + self.assertEqual(other2Keep.loadAllRemoteData(), {}) + + other2 = self.createRoadStack(data=other2Data, + eid=0, + main=None, + ha=("", 7532), + keep=other2Keep) + + console.terse("{0} keep dirpath = {1}\n".format( + other2.name, other2.keep.dirpath)) + self.assertTrue(other2.keep.dirpath.endswith('other2/raet/other2')) + self.assertEqual(other2.local.ha, ("0.0.0.0", 7532)) + self.assertFalse(other2.keep.auto) + self.assertDictEqual(other2.keep.loadLocalData(), + { + 'uid': 0, + 'name': other2Data['name'], + 'ha': ['0.0.0.0', 7532], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': other1Data['sighex'], + 'prihex': other1Data['prihex'], + 'auto': False, + 'role': other2Data['role'], + }) + + # should join since same role and keys + self.join(other2, main) + + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.joined) + self.assertEqual(len(other2.transactions), 0) + remote = other2.remotes.values()[0] + self.assertTrue(remote.joined) + + self.allow(other2, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.allowed) + self.assertEqual(len(other2.transactions), 0) + remote = other2.remotes.values()[0] + self.assertTrue(remote.allowed) + + for remote in main.remotes.values(): + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertTrue(os.path.exists(path)) + + + # now delete a key and see if both road keep file are also deleted + main.keep.saltRaetKey.delete_key(match=other1.local.role) + remote = main.remotes[other1.local.uid] + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + remote = main.remotes[other2.local.uid] + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + + main.server.close() + other1.server.close() + other2.server.close() + + def testBootstrapRoleAuto(self): + ''' + Bootstap to allowed with multiple remotes using same role + ''' + console.terse("{0}\n".format(self.testBootstrapRoleAuto.__doc__)) + + opts = self.createOpts(name='main', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + mainData = self.createRoadData(name='main', cachedirpath=opts['cachedir'] ) + mainKeep = salting.SaltKeep(opts=opts, + basedirpath=mainData['basedirpath'], + stackname=mainData['name']) + + self.assertEqual(mainKeep.loadLocalData(), None) + self.assertEqual(mainKeep.loadAllRemoteData(), {}) + + main = self.createRoadStack(data=mainData, + eid=1, + main=True, + ha=None, #default ha is ("", raeting.RAET_PORT) + keep=mainKeep) + + console.terse("{0}\nkeep dirpath = {1}\n".format( + main.name, main.keep.dirpath)) + self.assertTrue(main.keep.dirpath.endswith('main/raet/main')) + self.assertTrue(main.local.ha, ("0.0.0.0", raeting.RAET_PORT)) + self.assertTrue(main.keep.auto) + self.assertDictEqual(main.keep.loadLocalData(), {'uid': 1, + 'name': mainData['name'], + 'ha': ['0.0.0.0', 7530], + 'main': True, + 'sid': 0, + 'neid': 1, + 'sighex': mainData['sighex'], + 'prihex': mainData['prihex'], + 'auto': True, + 'role': mainData['role'], + }) + + opts = self.createOpts(name='other1', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=True) + other1Data = self.createRoadData(name='other1', + cachedirpath=opts['cachedir'], + role='primary') + other1Keep = salting.SaltKeep(opts=opts, + basedirpath=other1Data['basedirpath'], + stackname=other1Data['name']) + + self.assertEqual(other1Keep.loadLocalData(), None) + self.assertEqual(other1Keep.loadAllRemoteData(), {}) + + other1 = self.createRoadStack(data=other1Data, + eid=0, + main=None, + ha=("", raeting.RAET_TEST_PORT), + keep=other1Keep) + + console.terse("{0} keep dirpath = {1}\n".format( + other1.name, other1.keep.dirpath)) + self.assertTrue(other1.keep.dirpath.endswith('other1/raet/other1')) + self.assertEqual(other1.local.ha, ("0.0.0.0", raeting.RAET_TEST_PORT)) + self.assertTrue(other1.keep.auto) + self.assertDictEqual(other1.keep.loadLocalData(), + { + 'uid': 0, + 'name': other1Data['name'], + 'ha': ['0.0.0.0', 7531], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': other1Data['sighex'], + 'prihex': other1Data['prihex'], + 'auto': True, + 'role': other1Data['role'], + }) + + self.join(other1, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.joined) + self.assertEqual(len(other1.transactions), 0) + remote = other1.remotes.values()[0] + self.assertTrue(remote.joined) + + self.allow(other1, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.allowed) + self.assertEqual(len(other1.transactions), 0) + remote = other1.remotes.values()[0] + self.assertTrue(remote.allowed) + + for remote in main.remotes.values(): + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertTrue(os.path.exists(path)) + + # create other2 stack but use same role and different keys as other1 + opts = self.createOpts(name='other2', + dirpath=self.tempDirpath, + openMode=False, + autoAccept=False) + other2Data = self.createRoadData(name='other2', + cachedirpath=opts['cachedir'], + role='primary') + other2Data['sighex'] = other1Data['sighex'] + other2Data['prihex'] = other1Data['prihex'] + + other2Keep = salting.SaltKeep(opts=opts, + basedirpath=other2Data['basedirpath'], + stackname=other2Data['name']) + + self.assertEqual(other2Keep.loadLocalData(), None) + self.assertEqual(other2Keep.loadAllRemoteData(), {}) + + other2 = self.createRoadStack(data=other2Data, + eid=0, + main=None, + ha=("", 7532), + keep=other2Keep) + + console.terse("{0} keep dirpath = {1}\n".format( + other2.name, other2.keep.dirpath)) + self.assertTrue(other2.keep.dirpath.endswith('other2/raet/other2')) + self.assertEqual(other2.local.ha, ("0.0.0.0", 7532)) + self.assertFalse(other2.keep.auto) + self.assertDictEqual(other2.keep.loadLocalData(), + { + 'uid': 0, + 'name': other2Data['name'], + 'ha': ['0.0.0.0', 7532], + 'main': None, + 'sid': 0, + 'neid': 1, + 'sighex': other2Data['sighex'], + 'prihex': other2Data['prihex'], + 'auto': False, + 'role': other2Data['role'], + }) + + # should join since same role and keys + self.join(other2, main) + + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.joined) + self.assertEqual(len(other2.transactions), 0) + remote = other2.remotes.values()[0] + self.assertTrue(remote.joined) + + self.allow(other2, main) + self.assertEqual(len(main.transactions), 0) + remote = main.remotes.values()[0] + self.assertTrue(remote.allowed) + self.assertEqual(len(other2.transactions), 0) + remote = other2.remotes.values()[0] + self.assertTrue(remote.allowed) + + for remote in main.remotes.values(): + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertTrue(os.path.exists(path)) + + + # now delete a key and see if both road keep file are also deleted + main.keep.saltRaetKey.delete_key(match=other1.local.role) + remote = main.remotes[other1.local.uid] + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + remote = main.remotes[other2.local.uid] + path = os.path.join(main.keep.remotedirpath, + "{0}.{1}.{2}".format(main.keep.prefix, remote.name, main.keep.ext)) + self.assertFalse(os.path.exists(path)) + + main.server.close() + other1.server.close() + other2.server.close() + def runOne(test): ''' Unittest Runner @@ -494,7 +1912,17 @@ def runSome(): ''' tests = [] names = ['testBasic', - 'testBootstrapClean', ] + 'testBasicOpen', + 'testBasicAuto', + 'testBasicRole', + 'testBasicRoleOpen', + 'testBasicRoleAuto', + 'testBootstrapClean', + 'testBootstrapOpen', + 'testBootstrapAuto', + 'testBootstrapRole', + 'testBootstrapRoleAuto', + ] tests.extend(map(BasicTestCase, names)) @@ -518,4 +1946,4 @@ if __name__ == '__main__' and __package__ is None: runSome()#only run some - #runOne('testBasic') + #runOne('testBootstrapRoleAuto') diff --git a/salt/key.py b/salt/key.py index b978ca39f3..32287f05ee 100644 --- a/salt/key.py +++ b/salt/key.py @@ -11,6 +11,8 @@ import stat import shutil import fnmatch import hashlib +import json +import msgpack # Import salt libs import salt.crypt @@ -827,9 +829,14 @@ class RaetKey(Key): prefix, sep, name = root.partition('.') if not name or prefix != 'estate': continue - if name not in minions: - path = os.path.join(road_cache, road) - os.remove(path) + path = os.path.join(road_cache, road) + with salt.utils.fopen(path, 'rb') as fp_: + if ext == '.json': + data = json.load(fp_) + elif ext == '.msgpack': + data = msgpack.load(fp_) + if data['role'] not in minions: + os.remove(path) def gen_keys(self): ''' @@ -876,13 +883,7 @@ class RaetKey(Key): 'device_id': device_id, 'pub': pub, 'verify': verify} - if self.opts['open_mode']: - if os.path.isfile(acc_path): - # The minion id has been accepted, verify the key strings - with salt.utils.fopen(acc_path, 'rb') as fp_: - keydata = self.serial.loads(fp_.read()) - if keydata['pub'] == pub and keydata['verify'] == verify: - return 'accepted' + if self.opts['open_mode']: # always accept and overwrite with salt.utils.fopen(acc_path, 'w+b') as fp_: fp_.write(self.serial.dumps(keydata)) return 'accepted'