def parse(self, data): """Parse @data based on separators and declared elements.""" # Different node pattern should be put on different nid_map lines if ',' in data: msg = "Do not use comma in nid_map: %s" % data raise ModelFileValueError(msg) ModelFile.parse(self, data)
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('dev', check='path') self.add_element('index', check='digit') self.add_element('jdev', check='path') self.add_element('mode', check='enum', default='managed', values=['managed', 'external'])
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('tag', check='string') self.add_element('node', check='string') self.add_element('ha_node', check='string', multiple=True) self.add_element('dev', check='path') self.add_element('size', check='digit') self.add_element('jdev', check='path') self.add_element('jsize', check='digit')
def test_huge_folding_scales(self): """folding a lot of elements is fast enough""" model = ModelFile() model.add_element("foo", check="string", multiple=True, fold=True) for i in range(0, 10000): model.parse('foo: first%s second%s' % (i, i + 10)) before = time.time() self.assertEqual(str(model), 'foo:first[0-9999] second[10-10009]') elapsed = time.time() - before self.assertTrue(elapsed < 0.5, "%.2fs exceeds 0.5s threshold" % elapsed)
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('node', check='string') self.add_element('ha_node', check='string', multiple=True) self.add_element('dev', check='path') self.add_element('jdev', check='path') self.add_element('index', check='digit') self.add_element('group', check='string') self.add_element('mode', check='enum', default='managed', values=['managed', 'external']) self.add_element('network', check='string') self.add_element('tag', check='string')
def __init__(self, sep=":", linesep="\n"): ModelFile.__init__(self, sep, linesep) # General self.add_custom('fs_name', FSName()) self.add_element('description', check='string') # Stripping self.add_element('stripe_size', check='digit', default=1048576) self.add_element('stripe_count', check='digit', default=1) # Common target options for tgt in ['mgt', 'mdt', 'ost']: self.add_element(tgt + "_mkfs_options", check='string') self.add_element(tgt + "_mount_options", check='string') self.add_element(tgt + "_format_params", check='string') self.add_element("mgt_mount_path", check='string', default='/mnt/$fs_name/mgt') self.add_element("mdt_mount_path", check='string', default='/mnt/$fs_name/mdt/$index') self.add_element("ost_mount_path", check='string', default='/mnt/$fs_name/ost/$index') # Common client options self.add_element('mount_options', check='string') self.add_element('mount_path', check='path') # Quota self.add_element('quota', check='boolean') self.add_element('quota_type', check='string', default='ug') self.add_element('quota_bunit', check='digit') self.add_element('quota_iunit', check='digit') self.add_element('quota_btune', check='digit') self.add_element('quota_itune', check='digit') # NidMapping self.add_custom('nid_map', NidMaps()) # Targets self.add_custom('mgt', Target(), multiple=True) self.add_custom('mdt', Target(), multiple=True) self.add_custom('ost', Target(), multiple=True) # Client self.add_custom('client', Client(), multiple=True) # Router self.add_custom('router', Router(), multiple=True)
def testMultipleElement(self): """ModelFile with MultipleElement""" model = ModelFile() model.add_element('foos', check='digit', multiple=True) # Default self.assertEqual(model.get('foos', []), []) # Multiple add() model.add('foos', 3) self.assertEqual(model.get('foos'), [3]) self.assertEqual(str(model), "foos:3") model.add('foos', 5) self.assertEqual(model.get('foos'), [3, 5]) self.assertEqual(str(model), "foos:3\nfoos:5")
def __init__(self, sep=":", linesep="\n"): ModelFile.__init__(self, sep, linesep) # General self.add_custom('fs_name', FSName()) self.add_element('description', check='string') # Stripping self.add_element('stripe_size', check='digit', default=1048576) self.add_element('stripe_count', check='digit', default=1) # Common target options for tgt in ['mgt', 'mdt', 'ost' ]: self.add_element(tgt + "_mkfs_options", check='string') self.add_element(tgt + "_mount_options", check='string') self.add_element(tgt + "_format_params", check='string') self.add_element("mgt_mount_path", check='string', default='/mnt/$fs_name/mgt') self.add_element("mdt_mount_path", check='string', default='/mnt/$fs_name/mdt/$index') self.add_element("ost_mount_path", check='string', default='/mnt/$fs_name/ost/$index') # Common client options self.add_element('mount_options', check='string') self.add_element('mount_path', check='path') # Quota self.add_element('quota', check='boolean') self.add_element('quota_type', check='string', default='ug') self.add_element('quota_bunit', check='digit') self.add_element('quota_iunit', check='digit') self.add_element('quota_btune', check='digit') self.add_element('quota_itune', check='digit') # NidMapping self.add_custom('nid_map', NidMaps()) # Targets self.add_custom('mgt', Target(), multiple=True) self.add_custom('mdt', Target(), multiple=True) self.add_custom('ost', Target(), multiple=True) # Client self.add_custom('client', Client(), multiple=True) # Router self.add_custom('router', Router(), multiple=True)
def testModelBaseMethods(self): """test ModelFile base methods""" model = ModelFile() # content() with a default value self.assertEqual(model.content('default'), 'default') model.add_element('foo', check='string', multiple=True) # get() with a default value self.assertEqual(model.get('foo', 'default'), 'default') # Only key with non-empty value are taken in account self.assertEqual(len(model), 0) # parse() self.assertRaises(ModelFileValueError, model.parse, "foo one two") # __contains__() False self.assertFalse('foo' in model) # iter() model.add('foo', "5 6") model.add('foo', "6 7") self.assertEqual(list(iter(model)), ['foo']) # __contains__() True self.assertTrue('foo' in model)
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('node', check='string') self.add_element('ha_node', check='string', multiple=True) self.add_element('dev', check='path') self.add_element('jdev', check='path') self.add_element('index', check='digit') self.add_element('group', check='string') self.add_element('mode', check='enum', default='managed', values=['managed', 'external']) self.add_element('network', check='string') self.add_element('tag', check='string') self.add_element('active', check='enum', default='yes', values=['yes', 'no', 'nocreate', 'manual'])
def __init__(self, sep="=", linesep="\n"): ModelFile.__init__(self, sep, linesep) # Backend stuff self.add_element('backend', check='enum', default='None', values=['ClusterDB', 'File', 'None']) self.add_element('storage_file', check='path', default='/etc/shine/storage.conf') self.add_element('status_dir', check='path', default='/var/cache/shine/status') # Config dirs self.add_element('conf_dir', check='path', default='/var/cache/shine/conf') self.add_element('lmf_dir', check='path', default='/etc/shine/models') self.add_element('tuning_file', check='path') # Timeouts self.add_element('ssh_connect_timeout', check='digit', default=30) self.add_element('ssh_fanout', check='digit', default=0) self.add_element('default_timeout', check='digit', default=30) # Commands self.add_element('command_path', check='path', default='/usr/lib/lustre') # Lustre version self.add_element('lustre_version', check='string') # CLI self.add_element('color', check='enum', default='auto', values=['never', 'always', 'auto']) # TO BE IMPLEMENTED self.add_element('start_timeout', check='digit') self.add_element('mount_timeout', check='digit') self.add_element('stop_timeout', check='digit') self.add_element('status_timeout', check='digit') self.add_element('log_file', check='path') self.add_element('log_level', check='string')
def testExpandRange(self): """parse ranged line expand correctly""" model = ModelFile() model.add_element("foo", check="string", multiple=True) model.parse("foo: mine[10-15]") self.assertEqual(len(model.get('foo')), 6) del model['foo'] model.parse("foo: mine[10-15] second[1-6]") self.assertEqual(len(model.get('foo')), 6) del model['foo'] # Ranges mismatch self.assertRaises(ModelFileValueError, model.parse, "foo: five[1-5] two[1-2]")
def __init__(self, sep="=", linesep="\n"): ModelFile.__init__(self, sep, linesep) # Backend stuff self.add_element('backend', check='enum', default='None', values=['ClusterDB', 'File', 'None']) self.add_element('storage_file', check='path', default='/etc/shine/storage.conf') self.add_element('status_dir', check='path', default='/var/cache/shine/status') # Config dirs self.add_element('conf_dir', check='path', default='/var/cache/shine/conf') self.add_element('lmf_dir', check='path', default='/etc/shine/models') self.add_element('tuning_file', check='path') # Timeouts self.add_element('ssh_connect_timeout', check='digit', default=30) self.add_element('ssh_fanout', check='digit', default=0) self.add_element('default_timeout', check='digit', default=30) # Commands self.add_element('command_path', check='path') # Lustre version self.add_element('lustre_version', check='string') # CLI self.add_element('color', check='enum', default='auto', values=['never', 'always', 'auto']) # TO BE IMPLEMENTED self.add_element('start_timeout', check='digit') self.add_element('mount_timeout', check='digit') self.add_element('stop_timeout', check='digit') self.add_element('status_timeout', check='digit') self.add_element('log_file', check='path') self.add_element('log_level', check='string')
def testDiffSimpleElement(self): """diff between 2 modelfiles with a SimpleElement""" model = ModelFile() model.add_element('name', check='string') model2 = model.emptycopy() # Empty models have no difference added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Same model have no difference model.add('name', 'foo') model2.add('name', 'foo') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # A value changed del model2['name'] model2.add('name', 'bar') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {'name': 'bar'}) # A value added del model['name'] added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {'name': 'bar'}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # A value removed added, changed, removed = model2.diff(model) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {'name': 'bar'}) self.assertEqual(changed.as_dict(), {})
def testLoadModelFromFile(self): """load a ModelFile from file""" model = ModelFile() model.add_element("foo", check="string", multiple=True) model.add_element("bar", check="digit", multiple=True) testfile = makeTempFile("""foo: my test bar: 3 foo: another bar: 1 bar: 2""") model.load(testfile.name) self.assertEqual(model.get('foo'), ['my test', 'another']) self.assertEqual(model.get('bar'), [3, 1, 2]) # Bad file syntax testfile = makeTempFile("""foo bad file""") self.assertRaises(ModelFileValueError, model.load, testfile.name)
def testModelElementManagement(self): """add/del elements to a model file""" model = ModelFile() # Add an element model.add_element('foo', check='path') # Add another element with the same key raises an error self.assertRaises(KeyError, model.add_element, 'foo', check='string') # is_element() accessors self.assertTrue(model.is_element('foo')) # Undeclared an element model.del_element('foo') self.assertRaises(KeyError, model.del_element, 'foo') # Re-add an element model.add_element('foo', check='digit')
def testAddCustomElement(self): """model file uses a user-defined Element""" class ElemNodeSet(SimpleElement): def __init__(self, check='string', default=None, values=None): SimpleElement.__init__(self, 'string', default, values) def _validate(self, value): try: return NodeSet(value) except: raise ModelFileValueError model = ModelFile() model.add_custom('nodes', ElemNodeSet(), multiple=True) model.add_custom('nids', ElemNodeSet(), multiple=True) model.add('nodes', 'foo[1-5]') self.assertEqual(str(model), "nodes:foo[1-5]") self.assertEqual([str(item) for item in model.get('nodes')], [str(NodeSet('foo[1-5]'))]) self.assertRaises(ModelFileValueError, model.add, 'nodes', 'bad[15')
def test_hash_model_element(self): """check 2 different model element have different hashes.""" model = ModelFile() model.add_element('foo', check='string') model.add_element('bar', check='string') model2 = model.emptycopy() model.parse('foo: foo1') model.parse('bar: bar1') model2.parse('foo: foofoo') model2.parse('bar: barbar') self.assertEqual(hash(model), hash(model)) self.assertEqual(hash(model2), hash(model2)) self.assertNotEqual(hash(model), hash(model2))
def __init__(self, sep='=', linesep=" "): ModelFile.__init__(self, sep, linesep) self.add_element('node', check='string') self.add_element('data', check='string')
def testNoDeclarationError(self): """use of a non-declared element raises an error""" model = ModelFile() self.assertRaises(KeyError, model.get, 'foo')
def testDiffMultipleElement(self): """diff between 2 modelfiles with a MultipleElement""" model = ModelFile() model.add_element('name', check='string', multiple=True) model2 = model.emptycopy() # Empty models have no difference added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Same model have no difference model.add('name', 'foo') model2.add('name', 'foo') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Add a value model2.add('name', 'bar') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {'name': ['bar']}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Remove a value del model2['name'] model.add('name', 'bar') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {'name': ['foo', 'bar']}) self.assertEqual(changed.as_dict(), {})
def testCompoundElement(self): """test a ModelFile with a compound element""" class MyCompound(ModelFile): def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('dev', check='path') self.add_element('index', check='digit') self.add_element('jdev', check='path') self.add_element('mode', check='enum', default='managed', values=['managed', 'external']) elem = MyCompound() elem.parse("dev=/dev/sdb jdev=/dev/sdc index=4") self.assertEqual(elem.get('dev'), '/dev/sdb') self.assertEqual(elem.get('jdev'), '/dev/sdc') self.assertEqual(elem.get('index'), 4) self.assertEqual(elem.get('mode'), 'managed') model = ModelFile() model.add_element('fsname', check='string') model.add_custom('mgt', MyCompound(), multiple=True) model.add_custom('mdt', MyCompound(), multiple=True) model.add_custom('ost', MyCompound(), multiple=True) model.parse("ost: dev=/dev/sdb index=4") self.assertEqual(len(model.get('ost')), 1) self.assertEqual(model.get('ost')[0].get('dev'), '/dev/sdb') self.assertEqual(model.get('ost')[0].get('index'), 4) model.parse("ost: dev=/dev/sdd index=5") self.assertEqual(len(model.get('ost')), 2) self.assertEqual(model.get('ost')[1].get('dev'), '/dev/sdd') self.assertEqual(model.get('ost')[1].get('index'), 5) # test hexadecimal index model.parse("ost: dev=/dev/sde index=0x12") self.assertEqual(len(model.get('ost')), 3) self.assertEqual(model.get('ost')[2].get('dev'), '/dev/sde') self.assertEqual(model.get('ost')[2].get('index'), 18) self.assertEqual( str(model), "ost:index=4 dev=/dev/sdb\n" "ost:index=5 dev=/dev/sdd\n" "ost:index=18 dev=/dev/sde")
def testModelStandardElement(self): """ModelFile with simple Element""" model = ModelFile() # Type string model.add_element('name', check='string') self.assertEqual(model.get('name', 'mine'), 'mine') model.add('name', 'foo') self.assertEqual(model.get('name'), 'foo') self.assertEqual(str(model), "name:foo") # Default value model.add_element('bar', check='string', default='barbar') self.assertEqual(model.get('bar'), 'barbar') self.assertEqual(model.get('bar', 'mine'), 'barbar') # Default value are not used for string representation self.assertEqual(str(model), "name:foo") # Type digit model.add_element('stripe_count', check='digit', default=1) self.assertEqual(model.get('stripe_count'), 1) model.add('stripe_count', 2) self.assertEqual(model.get('stripe_count'), 2) self.assertEqual(str(model), "name:foo\nstripe_count:2")
def test_expand_range(self): """parse ranged line expand correctly""" model = ModelFile() model.add_element("foo", check="string", multiple=True) model.parse("foo: mine[10-15]") self.assertEqual(len(model.get('foo')), 6) del model['foo'] model.parse("foo: mine[10-15] second[1-6]") self.assertEqual(len(model.get('foo')), 6) del model['foo'] # Range supports padding model.parse('foo: bar[01-02]') self.assertEqual(model.get('foo'), ['bar01', 'bar02']) del model['foo'] # Ranges mismatch self.assertRaises(ModelFileValueError, model.parse, "foo: five[1-5] two[1-2]")
def test_various_fold_range(self): """fold complex patterns involving ordering""" model = ModelFile() model.add_element("foo", check="string", multiple=True, fold=True) # Folding without digit is fine model.parse('foo: cat') model.parse('foo: dog') self.assertEqual(len(model.get('foo')), 2) self.assertEqual(str(model.elements('foo')), 'cat\ndog') copy = model.emptycopy() copy.parse(str(model)) self.assertEqual(copy, model) del model['foo'] # Keeps order model.parse('foo: foo1') model.parse('foo: foo3') model.parse('foo: foo2') self.assertEqual(len(model.get('foo')), 3) self.assertEqual(str(model.elements('foo')), 'foo[1,3]\nfoo2') copy = model.emptycopy() copy.parse(str(model)) self.assertEqual(copy, model) del model['foo'] # Complex ordering model.parse("foo: mine[10-15] second[1-6]") model.parse("foo: mine[8] second[7]") model.parse("foo: mine[16] second[8]") self.assertEqual(len(model.get('foo')), 8) self.assertEqual(str(model.elements('foo')), 'mine[10-15] second[1-6]\n' 'mine[8,16] second[7-8]') copy = model.emptycopy() copy.parse(str(model)) self.assertEqual(copy, model) del model['foo'] # Static column model.parse("foo: mine[10-15] second1") model.parse("foo: mine[16] second1") model.parse("foo: mine[16] second2") self.assertEqual(len(model.get('foo')), 8) self.assertEqual(str(model.elements('foo')), 'mine[10-16] second1\n' 'mine16 second2') copy = model.emptycopy() copy.parse(str(model)) self.assertEqual(copy, model) del model['foo']
def testDiffDictMultipleElement(self): """diff between 2 modelfiles with a multiple subelement""" model = ModelFile() element = ModelFile(sep="=", linesep=" ") element.add_element('dev', check='string') element.add_element('index', check='digit') model.add_custom('target', element, multiple=True) model2 = model.emptycopy() # Empty models have no difference added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Same model have no difference model.parse('target: dev=/dev/sda index=1') model2.parse('target: dev=/dev/sda index=1') self.assertEqual(len(model['target']), 1) self.assertEqual(len(model2['target']), 1) added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Add a new element model2.parse('target: dev=/dev/sdb index=2') self.assertEqual(len(model['target']), 1) self.assertEqual(len(model2['target']), 2) added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {'target': [{'index': 2, 'dev': '/dev/sdb'}]}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Change an element del model2['target'] model2.parse('target: dev=/dev/sdb index=1') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {'target': [{'index': 1, 'dev': '/dev/sdb'}]}) self.assertEqual(removed.as_dict(), {'target': [{'index': 1, 'dev': '/dev/sda'}]}) self.assertEqual(changed.as_dict(), {})
def testSaveModelToFile(self): """save a ModelFile to a file""" testfile = makeTempFile("""foo: my test bar: 3 foo: another bar: 1 bar: 2""") # Create a model model = ModelFile() model.add_element("foo", check="string", multiple=True) model.add_element("bar", check="digit", multiple=True) # Load a test file model.load(testfile.name) # Save it to a new file filename = makeTempFilename() model.save(filename, "# Some header") # Reload the file in another model model2 = model.emptycopy() model2.load(filename) os.unlink(filename) # Compare the two files. They should have no difference added, changed, removed = model.diff(model2) self.assertTrue(len(changed) == len(added) == len(removed) == 0)
def __init__(self, sep=":", linesep="\n"): ModelFile.__init__(self, sep, linesep) self.add_custom('mgt', FileDevice(), multiple=True) self.add_custom('mdt', FileDevice(), multiple=True) self.add_custom('ost', FileDevice(), multiple=True)
def testDiffDictMultipleElement(self): """diff between 2 modelfiles with a multiple subelement""" model = ModelFile() element = ModelFile(sep="=", linesep=" ") element.add_element('dev', check='string') element.add_element('index', check='digit') model.add_custom('target', element, multiple=True) model2 = model.emptycopy() # Empty models have no difference added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Same model have no difference model.parse('target: dev=/dev/sda index=1') model2.parse('target: dev=/dev/sda index=1') self.assertEqual(len(model['target']), 1) self.assertEqual(len(model2['target']), 1) added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Add a new element model2.parse('target: dev=/dev/sdb index=2') self.assertEqual(len(model['target']), 1) self.assertEqual(len(model2['target']), 2) added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {'target': [{ 'index': 2, 'dev': '/dev/sdb' }]}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Change an element del model2['target'] model2.parse('target: dev=/dev/sdb index=1') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {'target': [{ 'index': 1, 'dev': '/dev/sdb' }]}) self.assertEqual(removed.as_dict(), {'target': [{ 'index': 1, 'dev': '/dev/sda' }]}) self.assertEqual(changed.as_dict(), {})
def testModelBaseMethods(self): """test ModelFile base methods""" model = ModelFile() # content() with a default value self.assertEqual(model.content('default'), 'default') model.add_element('foo', check='string', multiple=True) # get() with a default value self.assertEqual(model.get('foo', 'default'), 'default') # Only key with non-empty value are taken in account self.assertEqual(len(model), 0) # parse() bad syntax self.assertRaises(ModelFileValueError, model.parse, "foo one two") # parse() with good syntax, but unknown key self.assertRaises(ModelFileValueError, model.parse, "good: syntax") # __contains__() False self.assertFalse('foo' in model) # iter() model.add('foo', "5 6") model.add('foo', "6 7") self.assertEqual(list(iter(model)), ['foo']) # __contains__() True self.assertTrue('foo' in model) # replace() model.replace('foo', "other") self.assertEqual(model.get('foo'), ['other']) # __eq__() other = model.emptycopy() self.assertNotEqual(model, other) other.add("foo", "other") self.assertEqual(model, other) self.assertNotEqual(model, "bad type object")
def testDiffDictElement(self): """diff between 2 modelfiles with a subelement""" model = ModelFile() element = ModelFile(sep="=", linesep=" ") element.add_element('size', check='digit') element.add_element('count', check='digit') model.add_custom('stripe', element) model2 = model.emptycopy() # Empty models have no difference added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Same model have no difference model.parse('stripe: count=1 size=1000000') model2.parse('stripe: count=1 size=1000000') added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {}) # Remove an attribute del model2.get('stripe')['count'] added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {'stripe': {'count': 1}}) self.assertEqual(changed.as_dict(), {}) # Change an attribute model2.get('stripe').add('count', 2) added, changed, removed = model.diff(model2) self.assertEqual(added.as_dict(), {}) self.assertEqual(removed.as_dict(), {}) self.assertEqual(changed.as_dict(), {'stripe': {'count': 2}})
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('nodes', check='string') self.add_element('nids', check='string')
def testCompoundElement(self): """test a ModelFile with a compound element""" class MyCompound(ModelFile): def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('dev', check='path') self.add_element('index', check='digit') self.add_element('jdev', check='path') self.add_element('mode', check='enum', default='managed', values=['managed', 'external']) elem = MyCompound() elem.parse("dev=/dev/sdb jdev=/dev/sdc index=4") self.assertEqual(elem.get('dev'), '/dev/sdb') self.assertEqual(elem.get('jdev'), '/dev/sdc') self.assertEqual(elem.get('index'), 4) self.assertEqual(elem.get('mode'), 'managed') model = ModelFile() model.add_element('fsname', check='string') model.add_custom('mgt', MyCompound(), multiple=True) model.add_custom('mdt', MyCompound(), multiple=True) model.add_custom('ost', MyCompound(), multiple=True) model.parse("ost: dev=/dev/sdb index=4") self.assertEqual(len(model.get('ost')), 1) self.assertEqual(model.get('ost')[0].get('dev'), '/dev/sdb') self.assertEqual(model.get('ost')[0].get('index'), 4) model.parse("ost: dev=/dev/sdd index=5") self.assertEqual(len(model.get('ost')), 2) self.assertEqual(model.get('ost')[1].get('dev'), '/dev/sdd') self.assertEqual(model.get('ost')[1].get('index'), 5) # test hexadecimal index model.parse("ost: dev=/dev/sde index=0x12") self.assertEqual(len(model.get('ost')), 3) self.assertEqual(model.get('ost')[2].get('dev'), '/dev/sde') self.assertEqual(model.get('ost')[2].get('index'), 18) self.assertEqual(str(model), "ost:index=4 dev=/dev/sdb\n" "ost:index=5 dev=/dev/sdd\n" "ost:index=18 dev=/dev/sde")
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('node', check='string') self.add_element('mount_options', check='string') self.add_element('mount_path', check='path')
def test_expand_fold_range(self): """parse line with range expand and fold correctly""" model = ModelFile() model.add_element("foo", check="string", multiple=True, fold=True) model.parse("foo: mine[10-15]") self.assertEqual(len(model.get('foo')), 6) self.assertEqual(str(model.elements('foo')), 'mine[10-15]') del model['foo'] model.parse("foo: mine[10-15] second[1-6]") self.assertEqual(len(model.get('foo')), 6) self.assertEqual(str(model.elements('foo')), 'mine[10-15] second[1-6]') del model['foo'] # Range supports padding model.parse('foo: bar[01-02]') self.assertEqual(model.get('foo'), ['bar01', 'bar02']) self.assertEqual(str(model.elements('foo')), 'bar[01-02]') del model['foo'] # Ranges mismatch self.assertRaises(ModelFileValueError, model.parse, "foo: five[1-5] two[1-2]")
def __init__(self, sep='=', linesep=' '): ModelFile.__init__(self, sep, linesep) self.add_element('node', check='string')