github.com/deemoprobe/k8s-first-commit@v0.0.0-20230430165612-a541f1982be3/src/saltbase/salt/_states/container_bridge.py (about)

     1  # Copyright 2014 Google Inc. All rights reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  import re
    16  
    17  import salt.exceptions
    18  import salt.utils.ipaddr as ipaddr
    19  
    20  def ensure(name, cidr, mtu=1460):
    21      '''
    22      Ensure that a bridge (named <name>) is configured for contianers.
    23  
    24      Under the covers we will make sure that
    25        - The bridge exists
    26        - The MTU is set
    27        - The correct network is added to the bridge
    28        - iptables is set up for MASQUARADE for egress
    29  
    30      cidr:
    31          The cidr range in the form of 10.244.x.0/24
    32      mtu:
    33          The MTU to set on the interface
    34      '''
    35      ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
    36  
    37      iptables_rule = {
    38          'table': 'nat',
    39          'chain': 'POSTROUTING',
    40          'rule': '-o eth0 -j MASQUERADE \! -d 10.0.0.0/8'
    41      }
    42  
    43      def bridge_exists(name):
    44          'Determine if a bridge exists already.'
    45          out = __salt__['cmd.run_stdout']('brctl show {0}'.format(name))
    46          for line in out.splitlines():
    47              # get rid of first line
    48              if line.startswith('bridge name'):
    49                  continue
    50              # get rid of ^\n's
    51              vals = line.split()
    52              if not vals:
    53                  continue
    54              if len(vals) > 1:
    55                  return True
    56          return False
    57  
    58      def get_ip_addr_details(name):
    59          'For the given interface, get address details.'
    60          out = __salt__['cmd.run']('ip addr show dev {0}'.format(name))
    61          ret = { 'networks': [] }
    62          for line in out.splitlines():
    63              match = re.match(
    64                  r'^\d*:\s+([\w.\-]+)(?:@)?([\w.\-]+)?:\s+<(.+)>.*mtu (\d+)',
    65                  line)
    66              if match:
    67                  iface, parent, attrs, mtu = match.groups()
    68                  if 'UP' in attrs.split(','):
    69                      ret['up'] = True
    70                  else:
    71                      ret['up'] = False
    72                  if parent:
    73                      ret['parent'] = parent
    74                  ret['mtu'] = int(mtu)
    75                  continue
    76              cols = line.split()
    77              if len(cols) > 2 and cols[0] == 'inet':
    78                  ret['networks'].append(cols[1])
    79          return ret
    80  
    81  
    82      def get_current_state():
    83          'Helper that returns a dict of current bridge state.'
    84          ret = {}
    85          ret['name'] = name
    86          ret['exists'] = bridge_exists(name)
    87          if ret['exists']:
    88              ret['details'] = get_ip_addr_details(name)
    89          else:
    90              ret['details'] = {}
    91          # This module function is strange and returns True if the rule exists.
    92          # If not, it returns a string with the error from the call to iptables.
    93          ret['iptables_rule_exists'] = \
    94            __salt__['iptables.check'](**iptables_rule) == True
    95          return ret
    96  
    97      # This is a little hacky.  I should probably import a real library for this
    98      # but this'll work for now.
    99      try:
   100          cidr_network = ipaddr.IPv4Network(cidr, strict=True)
   101      except Exception:
   102          raise salt.exceptions.SaltInvocationError(
   103              'Invalid CIDR \'{0}\''.format(cidr))
   104  
   105      desired_network = '{0}/{1}'.format(
   106          str(ipaddr.IPv4Address(cidr_network._ip + 1)),
   107          str(cidr_network.prefixlen))
   108  
   109      current_state = get_current_state()
   110  
   111      if (current_state['exists']
   112          and current_state['details']['mtu'] == mtu
   113          and desired_network in current_state['details']['networks']
   114          and current_state['details']['up']
   115          and current_state['iptables_rule_exists']):
   116          ret['result'] = True
   117          ret['comment'] = 'System already in the correct state'
   118          return ret
   119  
   120      # The state of the system does need to be changed. Check if we're running
   121      # in ``test=true`` mode.
   122      if __opts__['test'] == True:
   123          ret['comment'] = 'The state of "{0}" will be changed.'.format(name)
   124          ret['changes'] = {
   125              'old': current_state,
   126              'new': 'Create and configure bridge'
   127          }
   128  
   129          # Return ``None`` when running with ``test=true``.
   130          ret['result'] = None
   131  
   132          return ret
   133  
   134      # Finally, make the actual change and return the result.
   135      if not current_state['exists']:
   136          __salt__['cmd.run']('brctl addbr {0}'.format(name))
   137      new_state = get_current_state()
   138      if new_state['details']['mtu'] != mtu:
   139          __salt__['cmd.run'](
   140              'ip link set dev {0} mtu {1}'.format(name, str(mtu)))
   141      new_state = get_current_state()
   142      if desired_network not in new_state['details']['networks']:
   143          __salt__['cmd.run'](
   144              'ip addr add {0} dev {1}'.format(desired_network, name))
   145      new_state = get_current_state()
   146      if not new_state['details']['up']:
   147          __salt__['cmd.run'](
   148              'ip link set dev {0} up'.format(name))
   149      new_state = get_current_state()
   150      if not new_state['iptables_rule_exists']:
   151          __salt__['iptables.append'](**iptables_rule)
   152      new_state = get_current_state()
   153  
   154      ret['comment'] = 'The state of "{0}" was changed!'.format(name)
   155  
   156      ret['changes'] = {
   157          'old': current_state,
   158          'new': new_state,
   159      }
   160  
   161      ret['result'] = True
   162  
   163      return ret