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