def test_select_raise_warning(self): # Check that the warning gets called upon if we select more than # one node, or not if we don't args = ['select', 'cluster=appservers', 'set/pooled=yes'] original_raise_warning = tool.ToolCliByLabel.raise_warning tool.ToolCliByLabel.raise_warning = mock.MagicMock() with self.assertRaises(SystemExit) as cm: tool.main(cmdline=args) self.assertEqual(cm.exception_code, 0) self.assertEqual(tool.ToolCliByLabel.raise_warning.call_count, 1) # now let's loop through the responses from conftool get args = ['select', 'cluster=appservers', 'get'] for res in self.output_for(args): _log.debug(res) del res['tags'] k = list(res.keys())[0] self.assertEqual(res[k]['pooled'], 'yes') tool.ToolCliByLabel.raise_warning.reset_mock() args = ['select', 'name=mw1018', 'set/pooled=inactive'] with self.assertRaises(SystemExit) as cm: tool.main(cmdline=args) self.assertEqual(cm.exception_code, 0) tool.ToolCliByLabel.raise_warning.assert_not_called() out = self.output_for(['select', 'name=mw1018', 'get']) self.assertEqual(out[0]['mw1018']['pooled'], 'inactive') tool.ToolCliByLabel.raise_warning = original_raise_warning
def load_nodes(dc, data, lock): # Read data and arrange them in the form we expect for cluster, cl_data in data.items(): cl = defaultdict(list) for host, services in cl_data.items(): for servname in services: cl[servname].append(host) for servname, hosts in cl.items(): new_nodes, del_nodes = get_changed_nodes(dc, cluster, servname, hosts) path = node.Node.dir(dc, cluster, servname) with lock(path): for el in new_nodes: _log.debug("See if %s is present", el) load_node(dc, cluster, servname, el) for el in del_nodes: _log.debug("See if %s should be deleted", el) delete_node(dc, cluster, servname, el)
def load(self): # Now we have all the data, let's translate those to tags/entities to_load, self.to_remove = self.get_changes(self.data) for key in to_load: tags = key.split('/') _log.debug("Loading %s:%s", self.entity, key) obj = self.cls(*tags) if obj.static_values: _log.info("Syncing static object %s:%s", self.entity, key) obj.validate(self.data[key]) obj.from_net(self.data[key]) else: if obj.exists: # For some reason, the object already exists, do nothing _log.warning("Not loading %s:%s: object already exists") continue else: _log.info("Creating %s with tags %s", self.entity, key) obj.write()
def query(cls, query): """ Return all matching object given a tag:regexp dictionary as a query If any tag (or the object name) are omitted, all of them are supposed to get selected. """ tags = cls._tags + ['name'] for labels in cls.backend.driver.all_keys(cls.base_path()): is_matching = True for i, tag in enumerate(tags): regex = query.get(tag, None) if regex is None: # Label selector not specified, we catch anything continue if not regex.match(labels[i]): _log.debug("label %s did not match regex %s", labels[i], regex.pattern) is_matching = False break if is_matching: yield cls(*labels)
def from_file(cls, filename): """ Load a yaml file """ instance = cls() if not os.path.isfile(filename): return instance data = yaml_safe_load(filename, default={}) if not data: instance.has_errors = True return instance for objname, defs in data.items(): try: _log.debug('Loading entity %s', objname) entity_name = re.sub(r'\W', '_', objname.capitalize()) entity = factory(entity_name, defs) instance.entities[objname] = entity except Exception as e: _log.error('Could not load entity %s: %s', objname, e, exc_info=True) instance.has_errors = True return instance
def get_service_actions(cluster, data): exp_services = set(data.keys()) try: cl_dir = service.Service.dir(cluster) services = dict(KVObject.backend.driver.ls(cl_dir)) except ValueError: services = {} act_services = set(services.keys()) del_services = act_services - exp_services new_services = exp_services - act_services changed_services = set([ el for el in (act_services & exp_services) if services[el] != data[el] ]) _log.debug("Changed services in cluster %s: %s", cluster, " ".join(changed_services)) _log.debug("New services in cluster %s: %s", cluster, " ".join(new_services)) _log.debug("Services to remove in cluster %s: %s", cluster, " ".join(del_services)) return (new_services | changed_services, del_services)
def add(self, name, entity, dep_chain=None): """ Adds a class to the syncing list resolving its dependencies""" if dep_chain is None: dep_chain = [] # Check if we're re-adding an already inserted entity _log.debug("Adding %s, dep_chain %s", name, dep_chain) if not dep_chain and name in self.load_order: _log.debug("%s already added, skipping", name) return # Try to detect circular dependencies dep_chain.append(name) for dependency in entity.depends: _log.debug("Adding dependency %s first", dependency) if dependency in dep_chain: # this is a circular dependency, it is fatal raise ValueError("Dependency loop: %s=>%s" % ("=>".join(dep_chain), dependency)) if dependency in self.load_order: # this is already in the list of dependencies, we can bail out continue self.add(dependency, self.schema.entities[dependency], dep_chain=dep_chain) self.load_order.append(name)
def get_default(self, what): _log.debug("Setting default for %s", what) return self.service.get_defaults(what)