Statistics
| Branch: | Tag: | Revision:

root / qa / qa_iptables.py @ a07ae57f

History | View | Annotate | Download (3 kB)

1
#!/usr/bin/python -u
2
#
3

    
4
# Copyright (C) 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Manipulates nodes using `iptables` to simulate non-standard network
23
conditions.
24

25
"""
26

    
27
import uuid
28

    
29
import qa_config
30
import qa_utils
31

    
32
from qa_utils import AssertCommand
33

    
34
# String used as a comment for produced `iptables` results
35
IPTABLES_COMMENT_MARKER = "ganeti_qa_script"
36

    
37

    
38
class RulesContext(object):
39
  def __init__(self, nodes):
40
    self._nodes = set()
41

    
42
  def __enter__(self):
43
    self._marker = IPTABLES_COMMENT_MARKER + "_" + str(uuid.uuid4())
44
    return Rules(self)
45

    
46
  def __exit__(self, ext_type, exc_val, exc_tb):
47
    CleanRules(self._nodes, self._marker)
48

    
49
  def _AddNode(self, node):
50
    self._nodes.add(node)
51

    
52

    
53
class Rules(object):
54
  """Allows to introduce iptable rules and dispose them at the end of a block.
55

56
  Don't instantiate this class directly. Use `with RulesContext() as r` instead.
57
  """
58

    
59
  def __init__(self, ctx=None):
60
    self._ctx = ctx
61
    if self._ctx is not None:
62
      self._marker = self._ctx._marker
63
    else:
64
      self._marker = IPTABLES_COMMENT_MARKER
65

    
66
  def _AddNode(self, node):
67
    if self._ctx is not None:
68
      self._ctx._AddNode(node)
69

    
70
  def AppendRule(self, node, chain, rule, table="filter"):
71
    """Appends an `iptables` rule to a given node
72
    """
73
    AssertCommand(["iptables", "-t", table, "-A", chain] +
74
                  rule +
75
                  ["-m", "comment",
76
                   "--comment", self._marker],
77
                  node=node)
78
    self._AddNode(node)
79

    
80
  def RedirectPort(self, node, host, port, new_port):
81
    """Adds a rule to a master node that makes a destination host+port visible
82
    under a different port number.
83

84
    """
85
    self.AppendRule(node, "OUTPUT",
86
                    ["--protocol", "tcp",
87
                     "--destination", host, "--dport", str(port),
88
                     "--jump", "DNAT",
89
                     "--to-destination", ":" + str(new_port)],
90
                    table="nat")
91

    
92

    
93
GLOBAL_RULES = Rules()
94

    
95

    
96
def CleanRules(nodes, marker=IPTABLES_COMMENT_MARKER):
97
  """Removes all QA `iptables` rules matching a given marker from a given node.
98

99
  If no marker is given, the global default is used, which clean all custom
100
  markers.
101
  """
102
  if not hasattr(nodes, '__iter__'):
103
    nodes = [nodes]
104
  for node in nodes:
105
    AssertCommand(("iptables-save | grep -v '%s' | iptables-restore" %
106
                    (marker, )),
107
                  node=node)