def bipartition(self, node1, node2=None): """Creates a bi-directional partition between the two nodes.""" node1, node2 = self._get_node(node1), self._get_node(node2) if node2 is not None: return with_context(self._partition(node1, node2), self._partition(node2, node1)) else: disruptions = [] for name, ip in self._interfaces(): if name != node1: disruptions.append(self.bipartition(node1, name)) return with_context(*disruptions)
def partition_random(self): """Partitions a random node.""" node1 = self._random_interface()[0] node2 = self._random_interface()[0] while node1 == node2: node2 = self._random_interface() return with_context(self.bipartition(node1, node2))
def _corrupt(self, node, probability=.02): """Duplicates packets to the given node.""" probability = self._percentize(probability) logger.info("Corrupting packets to %s (probability=%s)", node, probability) self._run_in_container(node, 'tc', 'qdisc', 'add', 'dev', 'eth0', 'root', 'netem', 'corrupt', probability) return with_context(lambda: self.restore(node))
def corrupt(self, node=None, probability=.02): """Duplicates packets to the given node.""" if node is None: return with_context(*[ self._corrupt(name, probability) for name, ip in self._interfaces() ]) return self._corrupt(self._get_node(node), probability)
def duplicate(self, node=None, probability=.005, correlation=.05): """Duplicates packets to the given node.""" if node is None: return with_context(*[ self._duplicate(name, probability, correlation) for name, ip in self._interfaces() ]) return self._duplicate(self._get_node(node), probability, correlation)
def reorder(self, node=None, probability=.02, correlation=.5): """Reorders packets to the given node.""" if node is None: return with_context(*[ self._reorder(name, probability, correlation) for name, ip in self._interfaces() ]) return self._reorder(self._get_node(node), probability, correlation)
def _drop(self, node, probability=.02, correlation=.25): """Drops packets to the given node.""" probability, correlation = self._percentize( probability), self._percentize(correlation) logger.info("Dropping packets to %s (probability=%s, correlation=%s)", node, probability, correlation) self._run_in_container(node, 'tc', 'qdisc', 'add', 'dev', 'eth0', 'root', 'netem', 'loss', probability, correlation) return with_context(lambda: self.restore(node))
def partition_halves(self): """Partitions the network into two halves.""" disruptions = [] ips = self._interfaces() for i in range(len(ips)): if i % 2 == 0: for j in range(len(ips)): if i != j and j % 2 == 1: disruptions.append( self.bipartition(ips[i][0], ips[j][0])) return with_context(*disruptions)
def unipartition(self, local, remote=None): """Partitions the given local from the given remote.""" local, remote = self._get_node(local), self._get_node(remote) if remote is not None: return self._partition(local, remote) else: disruptions = [] for name, ip in self._interfaces(): if name != local: disruptions.append(self._partition(local, name)) return with_context(*disruptions)
def partition_isolate(self, node=None): """Isolates the given node from all its peers.""" if node is None: node = self._random_interface()[0] else: node = self._get_node(node) disruptions = [] for name, ip in self._interfaces(): if name != node: disruptions.append(self.bipartition(node, name)) return with_context(*disruptions)
def delay(self, node=None, latency=50, jitter=10, correlation=.75, distribution='normal'): """Delays packets to the given node.""" if node is None: return with_context(*[ self._delay(name, latency, jitter, correlation, distribution) for name, ip in self._interfaces() ]) return self._delay(self._get_node(node), latency, jitter, correlation, distribution)
def _delay(self, node, latency=50, jitter=10, correlation=.75, distribution='normal'): """Delays packets to the given node.""" latency, jitter, correlation = self._millize(latency), self._millize( jitter), self._percentize(correlation) logger.info( "Delaying packets to %s (latency=%s, jitter=%s, correlation=%s, distribution=%s)", node, latency, jitter, correlation, distribution) self._run_in_container(node, 'tc', 'qdisc', 'add', 'dev', 'eth0', 'root', 'netem', 'delay', latency, jitter, correlation, 'distribution', distribution) return with_context(lambda: self.restore(node))
def partition_bridge(self, node=None): """Partitions a node as a bridge to two sides of a cluster.""" if node is None: node = self._random_interface()[0] else: node = self._get_node(node) interfaces = self._interfaces() disruptions = [] for i in range(len(interfaces)): if i % 2 == 0 and interfaces[i][0] != node: for j in range(len(interfaces)): if i != j and j % 2 == 1 and interfaces[j][0] != node: disruptions.append( self.bipartition(interfaces[i][0], interfaces[j][0])) return with_context(*disruptions)
def _partition(self, local, remote): """Partitions the given local from the given remote.""" logger.info("Cutting off link %s->%s", local, remote) self._run_in_container(local, 'iptables', '-A', 'INPUT', '-s', self._get_ip(remote), '-j', 'DROP', '-w') return with_context(lambda: self.heal(local, remote))