Example #1
0
 def update(self, force=False):
     subnet = get_walt_subnet()
     devices = []
     for item in \
             self.db.execute(QUERY_DEVICES_WITH_IP).fetchall():
         device_ip = ip(item.ip)
         if device_ip not in subnet:
             continue
         if item.type != 'server':
             devices.append(dict(
                 type=item.type,
                 hostname=item.name,
                 ip=device_ip,
                 mac=item.mac,
                 netsetup=item.netsetup))
     conf = generate_dhcpd_conf(subnet, devices)
     with open(DHCPD_CONF_FILE, 'r') as conf_file:
         old_conf = conf_file.read()
     if conf != old_conf:
         with open(DHCPD_CONF_FILE, 'w') as conf_file:
             conf_file.write(conf)
         force = True # perform the restart below
     if force == True:
         do('service isc-dhcp-server restart')
         print('dhcpd conf updated.')
 def update(self, force=False):
     subnet = get_walt_subnet()
     devices = []
     for item in \
             self.db.execute(QUERY_DEVICES_WITH_IP).fetchall():
         device_ip = ip(item.ip)
         if device_ip not in subnet:
             continue
         if item.type != 'server':
             devices.append(dict(
                 type=item.type,
                 hostname=item.name,
                 ip=device_ip,
                 mac=item.mac,
                 netsetup=item.netsetup))
     conf = generate_dhcpd_conf(subnet, devices)
     with open(DHCPD_CONF_FILE, 'r') as conf_file:
         old_conf = conf_file.read()
     if conf != old_conf:
         with open(DHCPD_CONF_FILE, 'w') as conf_file:
             conf_file.write(conf)
         force = True # perform the restart below
     if force == True:
         do('service isc-dhcp-server restart')
         print 'dhcpd conf updated.'
Example #3
0
 def generate_device_keys(self, device_mac):
     device_id = 'vpn_' + device_mac.replace(':', '')
     with tempfile.TemporaryDirectory() as tmpdirname:
         do("ssh-keygen -C %(comment)s -N '' -t ecdsa -b 384 -f %(tmpdir)s/key"
            % dict(comment='walt-vpn@' + device_id, tmpdir=tmpdirname))
         do("ssh-keygen -s %(vpn_ca_key)s -I '%(device_id)s' -n %(principal)s %(tmpdir)s/key.pub"
            % dict(vpn_ca_key=str(VPN_CA_KEY),
                   device_id=device_id,
                   principal='walt-vpn',
                   tmpdir=tmpdirname))
         tmpdir = Path(tmpdirname)
         priv_key = (tmpdir / 'key').read_text()
         pub_cert_key = (tmpdir / 'key-cert.pub').read_text()
         return (priv_key, pub_cert_key)
 def try_kill_vnode(self, node_name):
     # get screen session
     # caution: "screen -S walt.node.vnode1 -X kill" may be ambiguous and
     # kill screen session of vnode10 instead of vnode1.
     # That's why we identify the full session name with "grep -ow".
     try:
         session_name = subprocess.check_output(
             'screen -ls | grep -ow "[[:digit:]]*.walt.node.%(name)s"' % \
             dict(name = node_name), shell=True).strip()
         do('screen -S "%(session)s" -X quit' % \
             dict(session = session_name))
     except subprocess.CalledProcessError:
         # screen session was probably manually killed
         return
 def try_kill_vnode(self, node_name):
     # get screen session
     # caution: "screen -S walt.node.vnode1 -X kill" may be ambiguous and
     # kill screen session of vnode10 instead of vnode1.
     # That's why we identify the full session name with "grep -ow".
     try:
         session_name = subprocess.check_output(
             'screen -ls | grep -ow "[[:digit:]]*.walt.node.%(name)s"' % \
             dict(name = node_name), shell=True).strip().decode(sys.stdout.encoding)
         do('screen -S "%(session)s" -X quit' % \
             dict(session = session_name))
     except subprocess.CalledProcessError:
         # screen session was probably manually killed
         return
    def netsetup_handler(self, requester, device_set, netsetup_value):
        # Interpret the node set, some of them may be strict devices
        device_infos = self.devices.parse_device_set(requester, device_set)
        if device_infos is None:
            yield False

        # Check the node set
        not_nodes = [di for di in device_infos if di.type != "node"]
        if len(not_nodes) > 0:
            msg = format_sentence(
                "%s is(are) not a() node(nodes), "
                "so it(they) does(do) not support the 'netsetup' setting.\n",
                [d.name for d in not_nodes], None, 'Device', 'Devices')
            requester.stderr.write(msg)
            yield False

        # Interpret the value
        new_netsetup_state = None
        try:
            new_netsetup_state = NetSetup(netsetup_value)
        except ValueError:
            requester.stderr.write(
                "'%s' is not a valid setting value for netsetup." %
                (netsetup_value))
            yield False

        # Yield information that all things have ran correctly
        yield True

        # Effectively configure nodes
        for node_info in device_infos:
            if node_info.netsetup == new_netsetup_state:
                # skip this node: already configured
                continue
            # Update the database
            self.db.update("nodes",
                           "mac",
                           mac=node_info.mac,
                           netsetup=new_netsetup_state)
            # Update iptables
            do("iptables %(action)s WALT --source '%(ip)s' --jump ACCEPT" %
               dict(ip=node_info.ip,
                    action="--insert"
                    if new_netsetup_state == NetSetup.NAT else "--delete"))
            # Validate the modifications
            self.db.commit()
Example #7
0
 def verify_conf(self):
     home_dir = WALT_VPN_USER['home_dir']
     if not home_dir.exists():  # if not configured
         # create user walt-vpn
         home_dir = WALT_VPN_USER['home_dir']
         do("useradd -U -d %(home_dir)s walt-vpn" %
            dict(home_dir=str(home_dir)))
         # generate VPN CA key
         VPN_CA_KEY.parent.mkdir(parents=True)
         do("ssh-keygen -N '' -t ecdsa -b 521 -f %s" % str(VPN_CA_KEY))
         ca_pub_key = VPN_CA_KEY_PUB.read_text().strip()
         # create appropriate authorized_keys file
         authorized_keys_file = home_dir / '.ssh' / 'authorized_keys'
         authorized_keys_file.write_text(
             WALT_VPN_USER['authorized_keys_pattern'] %
             dict(ca_pub_key=ca_pub_key, unsecure_pub_key=UNSECURE_KEY_PUB))
         # fix owner to 'walt-vpn'
         chown_tree(home_dir, 'walt-vpn', 'walt-vpn')
    def netsetup_handler(self, requester, device_set, netsetup_value):
        # Interpret the node set, some of them may be strict devices
        device_infos = self.devices.parse_device_set(requester, device_set)
        if device_infos is None:
            yield False

        # Check the node set
        not_nodes = filter(lambda di: di.type != "node", device_infos)
        if len(not_nodes) > 0:
            msg = format_sentence("%s is(are) not a() node(nodes), "
                                  "so it(they) does(do) not support the 'netsetup' setting.\n",
                                  [d.name for d in not_nodes],
                                  None, 'Device', 'Devices')
            requester.stderr.write(msg)
            yield False

        # Interpret the value
        new_netsetup_state = None
        try:
            new_netsetup_state = NetSetup(netsetup_value)
        except ValueError:
            requester.stderr.write(
                "'%s' is not a valid setting value for netsetup." % (netsetup_value))
            yield False

        # Yield information that all things have ran correctly
        yield True

        # Effectively configure nodes
        for node_info in device_infos:
            if node_info.netsetup == new_netsetup_state:
                # skip this node: already configured
                continue
            # Update the database
            self.db.update("nodes", "mac", mac=node_info.mac, netsetup=new_netsetup_state)
            # Update iptables
            do("iptables %(action)s WALT --source '%(ip)s' --jump ACCEPT" %
               dict(ip=node_info.ip,
                    action="--insert" if new_netsetup_state == NetSetup.NAT else "--delete"))
            # Validate the modifications
            self.db.commit()
Example #9
0
def create_bridge_iface(br_iface, interfaces, state_file):
    do('ip link add %s type bridge' % br_iface)
    do('brctl stp %s on' % br_iface)
    if os.path.exists(get_mac_file(br_iface)):
        with open_mac_file(br_iface, 'r') as mac_file:
            mac = mac_file.readline()
    else:
        mac = get_random_mac()
        with open_mac_file(br_iface, 'w') as mac_file:
            mac_file.write(mac + '\n')
            mac_file.flush()
    do('ip link set dev %s address %s' % (br_iface, mac))
    for iface in interfaces:
        do('ip link set dev %s master %s' % (iface, br_iface))
    set_iface_up(br_iface)
    state_file.write(br_iface + '\n')
def create_bridge_iface(br_iface, interfaces, state_file):
    do('ip link add %s type bridge' % br_iface)
    do('brctl stp %s on' % br_iface)
    if os.path.exists(get_mac_file(br_iface)):
        with open_mac_file(br_iface, 'r') as mac_file:
            mac = mac_file.readline()
    else:
        mac = get_random_mac()
        with open_mac_file(br_iface, 'w') as mac_file:
            mac_file.write(mac + '\n')
            mac_file.flush()
    do('ip link set dev %s address %s' % (br_iface, mac))
    for iface in interfaces:
        do('ip link set dev %s master %s' % (iface, br_iface))
    set_iface_up(br_iface)
    state_file.write(br_iface + '\n')
 def prepare_ssh_access_for_ip(self, ip):
     cmd = CMD_ADD_SSH_KNOWN_HOST % dict(ip=ip)
     do(cmd)
Example #12
0
def setup_ip_conf(iface, ip_conf):
    if ip_conf == 'dhcp':
        do('dhclient %s' % iface)
    else:
        do('ip addr add %s dev %s' % (ip_conf, iface))
Example #13
0
def down(iface):
    with open_state_file(iface, 'r') as state_file:
        for line in state_file.readlines():
            sub_iface = line.strip()
            do('ip link del dev %s' % sub_iface)
    remove_state_file(iface)
 def cleanup_netsetup(self):
     # drop rules set by prepare_netsetup
     do("iptables --table nat --delete POSTROUTING "
        "! --out-interface walt-net --source %s "
        "--jump MASQUERADE" % str(get_walt_subnet()))
     do("iptables --delete FORWARD "
        "--in-interface walt-net "
        "--jump WALT")
     do("iptables --delete FORWARD "
        "--out-interface walt-net --match state --state RELATED,ESTABLISHED "
        "--jump ACCEPT")
     do("iptables --delete FORWARD "
        "--in-interface walt-net --out-interface walt-net "
        "--jump ACCEPT")
     do("iptables --flush WALT")
     do("iptables --delete-chain WALT")
 def prepare_netsetup(self):
     # force-create the chain WALT and assert it is empty
     do("iptables --new-chain WALT")
     do("iptables --flush WALT")
     do("iptables --append WALT --jump DROP")
     # allow traffic on the bridge (virtual <-> physical nodes)
     do("iptables --append FORWARD "
        "--in-interface walt-net --out-interface walt-net "
        "--jump ACCEPT")
     # allow connections back to WalT
     do("iptables --append FORWARD "
        "--out-interface walt-net --match state --state RELATED,ESTABLISHED "
        "--jump ACCEPT")
     # jump to WALT chain for other traffic
     do("iptables --append FORWARD "
        "--in-interface walt-net "
        "--jump WALT")
     # NAT nodes traffic that is allowed to go outside
     do("iptables --table nat --append POSTROUTING "
        "! --out-interface walt-net --source %s "
        "--jump MASQUERADE" % str(get_walt_subnet()))
     # Set the configuration of all NAT-ed nodes
     for node_ip in self.db.execute("""\
             SELECT ip FROM nodes
             INNER JOIN devices ON devices.mac = nodes.mac
             WHERE netsetup = %d;
             """ % NetSetup.NAT):
         do("iptables --insert WALT --source '%s' --jump ACCEPT" % node_ip)
def setup_ip_conf(iface, ip_conf):
    if ip_conf == 'dhcp':
        do('dhclient %s' % iface)
    else:
        do('ip addr add %s dev %s' % (
                ip_conf, iface))
def create_vlan_iface(raw_iface, vlan, vlan_iface, state_file):
    do('ip link add link %s name %s type vlan id %d' % \
        (raw_iface, vlan_iface, vlan))
    set_iface_up(vlan_iface)
    state_file.write(vlan_iface + '\n')
Example #18
0
def run_shell_cmd(cmd):
    do(cmd)
Example #19
0
def lldp_update():
    do('lldpcli update')
Example #20
0
def del_ip_from_interface(ip, subnet, intf):
    do('ip addr del %s/%d dev %s' % (ip, subnet.prefixlen, intf))
Example #21
0
def add_ip_to_interface(ip, subnet, intf):
    do('ip addr add %s/%d dev %s' % (ip, subnet.prefixlen, intf))
Example #22
0
def ensure_nfsd_is_running():
    if not succeeds('pidof nfsd >/dev/null'):
        do('service nfs-kernel-server restart')
Example #23
0
def create_dummy_iface(iface, state_file):
    do('ip link add %s type dummy' % iface)
    set_iface_up(iface)
    state_file.write(iface + '\n')
Example #24
0
def create_vlan_iface(raw_iface, vlan, vlan_iface, state_file):
    do('ip link add link %s name %s type vlan id %d' % \
        (raw_iface, vlan_iface, vlan))
    set_iface_up(vlan_iface)
    state_file.write(vlan_iface + '\n')
 def try_kill_vnode(self, node_mac):
     session_name = self.get_vnode_screen_session_name(node_mac)
     if session_name is not None:
         do('screen -S "%(session)s" -X quit' % \
             dict(session = session_name))
def create_dummy_iface(iface, state_file):
    do('ip link add %s type dummy' % iface)
    set_iface_up(iface)
    state_file.write(iface + '\n')
Example #27
0
def set_iface_up(iface):
    do('ip link set up dev %s' % iface)
    def set_device_config(self, requester, device_set, settings_args):
        # parse settings
        all_settings = {}
        for arg in settings_args:
            parts = arg.split('=')
            if len(parts) != 2:
                requester.stderr.write(
                    "Provide settings as `<setting name>=<setting value>` arguments.\n"
                )
                return
            all_settings[parts[0]] = parts[1]

        # ensure the device set is correct
        device_infos = self.server.devices.parse_device_set(
            requester, device_set)
        if device_infos is None:
            return  # issue already reported

        # ensure all settings are known and pass related checks
        for setting_name, setting_value in all_settings.items():

            # check the setting is known
            setting_info = self.settings_table.get(setting_name)
            if setting_info is None:
                requester.stderr.write(
                    "Unknown setting '%s'. See: 'walt help show device-config'\n"
                    % setting_name)
                return

            # verify this setting pass all checks
            category_check = self.category_checks[setting_info['category']]
            if not category_check(requester, device_infos, setting_name,
                                  setting_value, all_settings):
                return
            value_check = setting_info['value-check']
            if not value_check(requester, device_infos, setting_name,
                               setting_value, all_settings):
                return

        # effectively configure the devices
        should_reboot_nodes = False
        db_settings = all_settings.copy()
        for setting_name, setting_value in all_settings.items():
            if setting_name == 'netsetup':
                new_netsetup_state = NetSetup(setting_value)
                for node_info in device_infos:
                    if node_info.conf.get('netsetup', 0) == new_netsetup_state:
                        # skip this node: already configured
                        continue
                    # update iptables
                    do("iptables %(action)s WALT --source '%(ip)s' --jump ACCEPT"
                       % dict(ip=node_info.ip,
                              action="--insert" if new_netsetup_state
                              == NetSetup.NAT else "--delete"))
                db_settings['netsetup'] = int(new_netsetup_state)
                should_reboot_nodes = True
            elif setting_name == 'cpu.cores':
                db_settings['cpu.cores'] = int(setting_value)
                should_reboot_nodes = True  # update in DB (below) is enough
            elif setting_name == 'ram':
                should_reboot_nodes = True  # update in DB (below) is enough
            elif setting_name in ('lldp.explore', 'poe.reboots'):
                setting_value = (setting_value.lower() == 'true'
                                 )  # convert value to boolean
                db_settings[setting_name] = setting_value
            elif setting_name == 'snmp.version':
                db_settings[setting_name] = int(setting_value)
            elif setting_name == 'snmp.community':
                pass  # update in DB (below) is enough
            elif setting_name == 'type':
                for device_info in device_infos:
                    device_info = device_info._asdict()
                    device_info.update(requester=requester, type=setting_value)
                    self.server.devices.add_or_update(**device_info)
                # 'type' is a column of table 'devices', so this setting should not
                # be recorded in 'devices.conf' column
                del db_settings['type']

        # save in db
        new_vals = json.dumps(db_settings)
        for di in device_infos:
            self.server.db.execute(
                "update devices set conf = conf || %s::jsonb where mac = %s",
                (new_vals, di.mac))
        self.server.db.commit()

        # notify user
        if should_reboot_nodes:
            requester.stdout.write(
                'Done. Reboot node(s) to see new settings in effect.\n')
        else:
            requester.stdout.write('Done.\n')
Example #29
0
def ensure_root_key_exists():
    if not os.path.isfile(SERVER_KEY_PATH):
        do("ssh-keygen -q -t rsa -f %s -N ''" % SERVER_KEY_PATH)
Example #30
0
def ensure_nfsd_is_running():
    if not succeeds('pidof nfsd >/dev/null'):
        do('service nfs-kernel-server restart')
Example #31
0
def del_ip_from_interface(ip, subnet, intf):
    do('ip addr del %s/%d dev %s' % (ip, subnet.prefixlen, intf))
Example #32
0
def filter_out_8021q(iface_src, iface_dst):
    do(DOT1Q_FILTER % dict(src=iface_src, dst=iface_dst))
Example #33
0
def lldp_update():
    do('lldpcli update')
 def prepare_ssh_access_for_ip(self, ip):
     cmd = CMD_ADD_SSH_KNOWN_HOST % dict(ip = ip)
     do(cmd)
def down(iface):
    with open_state_file(iface, 'r') as state_file:
        for line in state_file.readlines():
            sub_iface = line.strip()
            do('ip link del dev %s' % sub_iface)
    remove_state_file(iface)
 def prepare_netsetup(self):
     # force-create the chain WALT and assert it is empty
     do("iptables --new-chain WALT")
     do("iptables --flush WALT")
     do("iptables --append WALT --jump DROP")
     # allow traffic on the bridge (virtual <-> physical nodes)
     do("iptables --append FORWARD "
        "--in-interface walt-net --out-interface walt-net "
        "--jump ACCEPT")
     # allow connections back to WalT
     do("iptables --append FORWARD "
        "--out-interface walt-net --match state --state RELATED,ESTABLISHED "
        "--jump ACCEPT")
     # jump to WALT chain for other traffic
     do("iptables --append FORWARD "
        "--in-interface walt-net "
        "--jump WALT")
     # NAT nodes traffic that is allowed to go outside
     do("iptables --table nat --append POSTROUTING "
        "! --out-interface walt-net --source %s "
        "--jump MASQUERADE" % str(get_walt_subnet()))
     # Set the configuration of all NAT-ed nodes
     for node_ip in self.db.execute("""\
             SELECT ip FROM nodes
             INNER JOIN devices ON devices.mac = nodes.mac
             WHERE netsetup = %d;
             """ % NetSetup.NAT):
         do("iptables --insert WALT --source '%s' --jump ACCEPT" % node_ip)
def filter_out_8021q(iface_src, iface_dst):
    do(DOT1Q_FILTER % dict(src=iface_src, dst=iface_dst))
 def cleanup_netsetup(self):
     # drop rules set by prepare_netsetup
     do("iptables --table nat --delete POSTROUTING "
        "! --out-interface walt-net --source %s "
        "--jump MASQUERADE" % str(get_walt_subnet()))
     do("iptables --delete FORWARD "
        "--in-interface walt-net "
        "--jump WALT")
     do("iptables --delete FORWARD "
        "--out-interface walt-net --match state --state RELATED,ESTABLISHED "
        "--jump ACCEPT")
     do("iptables --delete FORWARD "
        "--in-interface walt-net --out-interface walt-net "
        "--jump ACCEPT")
     do("iptables --flush WALT")
     do("iptables --delete-chain WALT")
def set_iface_up(iface):
    do('ip link set up dev %s' % iface)
Example #40
0
def add_ip_to_interface(ip, subnet, intf):
    do('ip addr add %s/%d dev %s' % (ip, subnet.prefixlen, intf))
Example #41
0
def ensure_root_key_exists():
    if not os.path.isfile(SERVER_KEY_PATH):
        do("ssh-keygen -q -t rsa -f %s -N ''" % SERVER_KEY_PATH)