Giuseppe Lavagetto has submitted this change and it was merged.
Change subject: confctl: allow regex expression and a global "all"
......................................................................
confctl: allow regex expression and a global "all"
Change-Id: I377d5476d16c8df416bfca58f750f99c643f8a8e
---
M conftool/__init__.py
M conftool/cli/tool.py
M conftool/tests/unit/__init__.py
A conftool/tests/unit/test_cli_tool.py
M conftool/tests/unit/test_node.py
M debian/changelog
M setup.py
7 files changed, 122 insertions(+), 38 deletions(-)
Approvals:
Giuseppe Lavagetto: Verified; Looks good to me, approved
diff --git a/conftool/__init__.py b/conftool/__init__.py
index 93456f7..9a28331 100644
--- a/conftool/__init__.py
+++ b/conftool/__init__.py
@@ -88,7 +88,7 @@
try:
setattr(self, key, validator(values[key]))
except Exception as e:
- _log.error("Value for key %s is invalid: %s",
+ _log.info("Value for key %s is invalid: %s",
key, e)
if set_defaults:
val = self.get_default(key)
diff --git a/conftool/cli/tool.py b/conftool/cli/tool.py
index 31e9fad..1ae4eaf 100644
--- a/conftool/cli/tool.py
+++ b/conftool/cli/tool.py
@@ -8,9 +8,51 @@
from conftool.drivers import BackendError
# TODO: auto import these somehow
from conftool import service, node
+import re
object_types = {"node": node.Node, "service": service.Service}
+
+def host_list(name, cur_dir, act):
+ warn = False
+ if name == "all":
+ leaves = KVObject.backend.driver.ls(cur_dir)
+ if act == "get":
+ print json.dumps(dict(leaves))
+ return []
+ else:
+ retval = leaves.keys()
+ warn = True
+ elif not name.startswith('re:'):
+ return [name]
+ else:
+ regex = name.replace('re:', '', 1)
+ try:
+ r = re.compile(regex)
+ except:
+ _log.critical("Invalid regexp: %s", regex)
+ sys.exit(1)
+ all = KVObject.backend.driver.ls(cur_dir).keys()
+ retval = [objname for objname in all if r.match(objname)]
+ warn = (len(all) <= 2 * len(retval))
+ if warn and act in ['set', 'del']:
+ raise_warning()
+ return retval
+
+def raise_warning():
+ if not sys.stdin.isatty() or not sys.stdout.isatty():
+ print "Destructive operations are not scriptable"
+ " and should be run from the command line"
+ sys.exit(1)
+
+ print "You are operating on more than half of the objects, this is "
+ "potentially VERY DANGEROUS: do you want to continue?"
+ print "If so, please type: 'Yes, I am sure of what I am doing.'"
+ a = raw_input("confctl>")
+ if a == "Yes, I am sure of what I am doing.":
+ return True
+ print "Aborting"
+ sys.exit(1)
def main(cmdline=None):
if cmdline is None:
@@ -32,7 +74,8 @@
choices=object_types.keys(), default='node')
parser.add_argument('--action', action="append", metavar="ACTIONS",
help="the action to take: "
- " [set/k1=v1:k2=v2...|get|delete] node", nargs=2,
+ " [set/k1=v1:k2=v2...|get|delete]"
+ " node|all|re:<regex>", nargs=2,
required=True)
parser.add_argument('--debug', action="store_true",
default=False, help="print debug info")
@@ -59,26 +102,24 @@
sys.exit(1)
for unit in args.action:
- try:
- act, name = unit
- if act == 'get' and name == "all":
- cur_dir = cls.dir(*tags)
- print json.dumps(dict(KVObject.backend.driver.ls(cur_dir)))
- return
- # Oh python I <3 you...
- arguments = list(tags)
- arguments.append(name)
- obj = cls(*arguments)
- a = action.Action(obj, act)
- msg = a.run()
- except action.ActionError as e:
- _log.error("Invalid action, reason: %s", str(e))
- except BackendError as e:
- _log.error("Failure writing to the kvstore: %s", str(e))
- except Exception as e:
- _log.error("Generic action failure: %s", str(e))
- else:
- print(msg)
+ act, n = unit
+ cur_dir = cls.dir(*tags)
+ for name in host_list(n, cur_dir, act):
+ try:
+ # Oh python I <3 you...
+ arguments = list(tags)
+ arguments.append(name)
+ obj = cls(*arguments)
+ a = action.Action(obj, act)
+ msg = a.run()
+ except action.ActionError as e:
+ _log.error("Invalid action, reason: %s", str(e))
+ except BackendError as e:
+ _log.error("Failure writing to the kvstore: %s", str(e))
+ except Exception as e:
+ _log.error("Generic action failure: %s", str(e))
+ else:
+ print(msg)
if __name__ == '__main__':
diff --git a/conftool/tests/unit/__init__.py b/conftool/tests/unit/__init__.py
index e69de29..aeb1efd 100644
--- a/conftool/tests/unit/__init__.py
+++ b/conftool/tests/unit/__init__.py
@@ -0,0 +1,14 @@
+from conftool import drivers
+
+
+class MockDriver(drivers.BaseDriver):
+
+ def __init__(self, config):
+ self.base_path = '/base_path/v2'
+
+
+class MockBackend(object):
+
+ def __init__(self, config):
+ self.config = config
+ self.driver = MockDriver(config)
diff --git a/conftool/tests/unit/test_cli_tool.py
b/conftool/tests/unit/test_cli_tool.py
new file mode 100644
index 0000000..4fefc74
--- /dev/null
+++ b/conftool/tests/unit/test_cli_tool.py
@@ -0,0 +1,36 @@
+import unittest
+import mock
+from conftool import KVObject, configuration
+from conftool.tests.unit import MockBackend
+from conftool.cli import tool
+
+class TestCliTool(unittest.TestCase):
+
+ def setUp(self):
+ KVObject.backend = MockBackend({})
+ KVObject.config = configuration.Config(driver="")
+
+ def _mock_list(self, values):
+ KVObject.backend.driver.ls = mock.MagicMock(return_value=values)
+
+
+ def test_get_hosts(self):
+ """Tests getting the host list"""
+ host_dir = {
+ 'cp1011.example.com': {'pooled': 'yes'},
+ 'cp1020.example.com': {'pooled': 'no'},
+ 'cp1014.local': {'pooled': 'no'}
+ }
+ self._mock_list(host_dir)
+ l = tool.host_list('simple', '/whatever', 'get')
+ self.assertEquals(l, ['simple'])
+ l = tool.host_list('all', '/whatever', 'dummy')
+ self.assertItemsEqual(l, host_dir.keys())
+ l = tool.host_list('all', '/whatever', 'get')
+ self.assertEquals(l, [])
+ l = tool.host_list('re:.*\.local', '/whatever', 'get')
+ self.assertEquals(l, ['cp1014.local'])
+ l = tool.host_list('re:cp10[1-2][0-3]', '/whatever', 'get')
+ self.assertItemsEqual(l, ['cp1011.example.com', 'cp1020.example.com'])
+ with self.assertRaises(SystemExit):
+ tool.host_list('all', '/something', 'set')
diff --git a/conftool/tests/unit/test_node.py b/conftool/tests/unit/test_node.py
index 974ec0d..28493c1 100644
--- a/conftool/tests/unit/test_node.py
+++ b/conftool/tests/unit/test_node.py
@@ -1,20 +1,8 @@
import unittest
import mock
from conftool import KVObject, node, service
-from conftool import configuration, drivers
-
-
-class MockDriver(drivers.BaseDriver):
-
- def __init__(self, config):
- self.base_path = '/base_path/v2'
-
-
-class MockBackend(object):
-
- def __init__(self, config):
- self.config = config
- self.driver = MockDriver(config)
+from conftool import configuration
+from conftool.tests.unit import MockBackend
class TestNode(unittest.TestCase):
@@ -30,7 +18,6 @@
def setUp(self):
KVObject.backend = MockBackend({})
KVObject.config = configuration.Config(driver="")
- pass
@mock.patch('conftool.node.Node.get_default')
def test_new_node(self, mocker):
diff --git a/debian/changelog b/debian/changelog
index a6f27cc..9776fbd 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-conftool (0.1.2) UNRELEASED; urgency=medium
+
+ * Added regexp matching of targets
+
+ -- Giuseppe Lavagetto <oblivian@flint> Fri, 26 Jun 2015 07:51:14 +0200
+
python-conftool (0.1.1) precise-wikimedia; urgency=medium
* Fix a bug introduced with performance improvements
diff --git a/setup.py b/setup.py
index 182e822..033ba41 100755
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@
setup(
name='conftool',
- version='0.1.1',
+ version='0.1.2',
description='Collection of tools to interoperate with distributed k/v
stores',
author='Joe',
author_email='[email protected]',
--
To view, visit https://gerrit.wikimedia.org/r/220536
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I377d5476d16c8df416bfca58f750f99c643f8a8e
Gerrit-PatchSet: 4
Gerrit-Project: operations/software/conftool
Gerrit-Branch: master
Gerrit-Owner: Giuseppe Lavagetto <[email protected]>
Gerrit-Reviewer: BBlack <[email protected]>
Gerrit-Reviewer: Giuseppe Lavagetto <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits