I'll update my vim configuration, thx.

2013/11/12 Hrvoje Ribicic <[email protected]>

> I did not notice this before, but your description has been wrapped at 80
> chars / line when it should have been wrapped at 72 / line.
>
> I will fix that, but otherwise LGTM, thanks!
>
>
> On Tue, Nov 12, 2013 at 3:41 PM, Petr Pudlak <[email protected]> wrote:
>
>> This patch adds the `ssh-port` option. If set to a non-standard port, the
>> QA
>> script sets up the default node group with this port, and before running
>> test
>> it adds `iptable` rules to all nodes so that the nodes see each other's
>> SSH
>> servers as running on this port. Their SSH configuration is _not_ changed
>> and
>> other machines see the nodes on 22 as before.
>>
>> The `iptable` rules are reset on each QA run, trying to preserve any
>> existing
>> rules (not created by the script) that might be present.
>>
>> Signed-off-by: Petr Pudlak <[email protected]>
>> ---
>>  qa/ganeti-qa.py   |   2 +
>>  qa/qa-sample.json |   4 +-
>>  qa/qa_group.py    |  48 ++++++++++++++++++++++++
>>  qa/qa_iptables.py | 107
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 160 insertions(+), 1 deletion(-)
>>  create mode 100644 qa/qa_iptables.py
>>
>> diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py
>> index bf26cc5..b62fe9d 100755
>> --- a/qa/ganeti-qa.py
>> +++ b/qa/ganeti-qa.py
>> @@ -181,6 +181,8 @@ def SetupCluster(rapi_user):
>>        # To support RAPI on an existing cluster we have to find out the
>> secret
>>        rapi_secret = _LookupRapiSecret(rapi_user)
>>
>> +  qa_group.ConfigureGroups()
>> +
>>    # Test on empty cluster
>>    RunTestIf("node-list", qa_node.TestNodeList)
>>    RunTestIf("instance-list", qa_instance.TestInstanceList)
>> diff --git a/qa/qa-sample.json b/qa/qa-sample.json
>> index fd28f38..f16d9ab 100644
>> --- a/qa/qa-sample.json
>> +++ b/qa/qa-sample.json
>> @@ -263,7 +263,9 @@
>>      "burnin-rename": "xen-test-rename",
>>      "burnin-reboot": true,
>>      "reboot-types": ["soft", "hard", "full"],
>> -    "use-iallocators": false
>> +    "use-iallocators": false,
>> +    "# Uncomment if you want to run the whole cluster on a different SSH
>> port": null,
>> +    "# ssh-port": 222
>>    },
>>
>>    "# vim: set syntax=javascript :": null
>> diff --git a/qa/qa_group.py b/qa/qa_group.py
>> index f11e512..da88602 100644
>> --- a/qa/qa_group.py
>> +++ b/qa/qa_group.py
>> @@ -24,9 +24,11 @@
>>  """
>>
>>  from ganeti import constants
>> +from ganeti import netutils
>>  from ganeti import query
>>  from ganeti import utils
>>
>> +import qa_iptables
>>  import qa_config
>>  import qa_utils
>>
>> @@ -41,6 +43,52 @@ def GetDefaultGroup():
>>    return groups.get("group-with-nodes",
>> constants.INITIAL_NODE_GROUP_NAME)
>>
>>
>> +def ConfigureGroups():
>> +  """Configures groups and nodes for tests such as custom SSH ports.
>> +
>> +  """
>> +
>> +  defgroup = GetDefaultGroup()
>> +  nodes = qa_config.get("nodes")
>> +  options = qa_config.get("options", {})
>> +
>> +  # Clear any old configuration
>> +  qa_iptables.CleanRules(nodes)
>> +
>> +  # Custom SSH ports:
>> +  ssh_port = options.get("ssh-port")
>> +  default_ssh_port = netutils.GetDaemonPort(constants.SSH)
>> +  if (ssh_port is not None) and (ssh_port != default_ssh_port):
>> +    ModifyGroupSshPort(qa_iptables.GLOBAL_RULES, defgroup, nodes,
>> ssh_port)
>> +
>> +
>> +def ModifyGroupSshPort(ipt_rules, group, nodes, ssh_port):
>> +  """Modifies the node group settings and sets up iptable rules.
>> +
>> +  For each pair of nodes add two rules that affect SSH connections from
>> one
>> +  to the other one.
>> +  The first one redirects port 22 to some unused port so that connecting
>> +  through 22 fails. The second redirects port `ssh_port` to port 22.
>> +  Together this results in master seeing the SSH daemons on the nodes on
>> +  `ssh_port` instead of 22.
>> +  """
>> +  default_ssh_port = netutils.GetDaemonPort(constants.SSH)
>> +  all_nodes = qa_config.get("nodes")
>> +  AssertCommand(["gnt-group", "modify",
>> +                 "--node-parameters=ssh_port=" + str(ssh_port),
>> +                 group])
>> +  for node in nodes:
>> +    ipt_rules.RedirectPort(node.primary, "localhost",
>> +                           default_ssh_port, 65535)
>> +    ipt_rules.RedirectPort(node.primary, "localhost",
>> +                           ssh_port, default_ssh_port)
>> +    for node2 in all_nodes:
>> +      ipt_rules.RedirectPort(node2.primary, node.primary,
>> +                             default_ssh_port, 65535)
>> +      ipt_rules.RedirectPort(node2.primary, node.primary,
>> +                             ssh_port, default_ssh_port)
>> +
>> +
>>  def TestGroupAddRemoveRename():
>>    """gnt-group add/remove/rename"""
>>    existing_group_with_nodes = GetDefaultGroup()
>> diff --git a/qa/qa_iptables.py b/qa/qa_iptables.py
>> new file mode 100644
>> index 0000000..a561039
>> --- /dev/null
>> +++ b/qa/qa_iptables.py
>> @@ -0,0 +1,107 @@
>> +#!/usr/bin/python -u
>> +#
>> +
>> +# Copyright (C) 2013 Google Inc.
>> +#
>> +# This program is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 2 of the License, or
>> +# (at your option) any later version.
>> +#
>> +# This program is distributed in the hope that it will be useful, but
>> +# WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +# General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with this program; if not, write to the Free Software
>> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>> +# 02110-1301, USA.
>> +
>> +
>> +"""Manipulates nodes using `iptables` to simulate non-standard network
>> +conditions.
>> +
>> +"""
>> +
>> +import uuid
>> +
>> +import qa_config
>> +import qa_utils
>> +
>> +from qa_utils import AssertCommand
>> +
>> +# String used as a comment for produced `iptables` results
>> +IPTABLES_COMMENT_MARKER = "ganeti_qa_script"
>> +
>> +
>> +class RulesContext(object):
>> +  def __init__(self, nodes):
>> +    self._nodes = set()
>> +
>> +  def __enter__(self):
>> +    self._marker = IPTABLES_COMMENT_MARKER + "_" + str(uuid.uuid4())
>> +    return Rules(self)
>> +
>> +  def __exit__(self, ext_type, exc_val, exc_tb):
>> +    CleanRules(self._nodes, self._marker)
>> +
>> +  def _AddNode(self, node):
>> +    self._nodes.add(node)
>> +
>> +
>> +class Rules(object):
>> +  """Allows to introduce iptable rules and dispose them at the end of a
>> block.
>> +
>> +  Don't instantiate this class directly. Use `with RulesContext() as r`
>> instead.
>> +  """
>> +
>> +  def __init__(self, ctx=None):
>> +    self._ctx = ctx
>> +    if self._ctx is not None:
>> +      self._marker = self._ctx._marker
>> +    else:
>> +      self._marker = IPTABLES_COMMENT_MARKER
>> +
>> +  def _AddNode(self, node):
>> +    if self._ctx is not None:
>> +      self._ctx._AddNode(node)
>> +
>> +  def AppendRule(self, node, chain, rule, table="filter"):
>> +    """Appends an `iptables` rule to a given node
>> +    """
>> +    AssertCommand(["iptables", "-t", table, "-A", chain] +
>> +                  rule +
>> +                  ["-m", "comment",
>> +                   "--comment", self._marker],
>> +                  node=node)
>> +    self._AddNode(node)
>> +
>> +  def RedirectPort(self, node, host, port, new_port):
>> +    """Adds a rule to a master node that makes a destination host+port
>> visible
>> +    under a different port number.
>> +
>> +    """
>> +    self.AppendRule(node, "OUTPUT",
>> +                    ["--protocol", "tcp",
>> +                     "--destination", host, "--dport", str(port),
>> +                     "--jump", "DNAT",
>> +                     "--to-destination", ":" + str(new_port)],
>> +                    table="nat")
>> +
>> +
>> +GLOBAL_RULES = Rules()
>> +
>> +
>> +def CleanRules(nodes, marker=IPTABLES_COMMENT_MARKER):
>> +  """Removes all QA `iptables` rules matching a given marker from a
>> given node.
>> +
>> +  If no marker is given, the global default is used, which clean all
>> custom
>> +  markers.
>> +  """
>> +  if not hasattr(nodes, '__iter__'):
>> +    nodes = [nodes]
>> +  for node in nodes:
>> +    AssertCommand(("iptables-save | grep -v '%s' | iptables-restore" %
>> +                    (marker, )),
>> +                  node=node)
>> --
>> 1.8.4.1
>>
>>
>
>
> Hrvoje Ribicic
> Ganeti Engineering
> Google Germany GmbH
> Dienerstr. 12, 80331, München
>
> Registergericht und -nummer: Hamburg, HRB 86891
> Sitz der Gesellschaft: Hamburg
> Geschäftsführer: Graham Law, Christine Elizabeth Flores
> Steuernummer: 48/725/00206
> Umsatzsteueridentifikationsnummer: DE813741370
>

Reply via email to