Exemple #1
0
def reloadChutes():
    """
    This function is called to restart any chutes that were running prior to the system being restarted.
    It waits for pdconfd to come up and report whether or not it failed to bring up any of the interfaces
    that existed before the power cycle. If pdconfd indicates something failed we then force a stop update
    in order to bring down all interfaces associated with that chute and mark it with a warning. 
    If the stop fails we mark the chute with a warning manually and change its state to stopped and save to 
    storage this isn't great as it could mean our system still has interfaces up associated with that chute.
    If pdconfd doesn't report failure we attempt to start the chute and if this fails we trust the abort process
    to restore the system to a consistent state and we manually mark the chute as stopped and add a warning to it.
    :param None
    :returns: (list) A list of update dicts to be used to create updateObjects that should be run before accepting new updates.
    """
    if not settings.PDCONFD_ENABLED:
        return []
    chuteStore = chutestorage.ChuteStorage()
    chutes = [ ch for ch in chuteStore.getChuteList() if ch.state == 'running']

    # Part of restoring the chute to its previously running state is reclaiming
    # IP addresses, interface names, etc. that it had previously.
    for chute in chutes:
        reclaimNetworkResources(chute)

    #We need to make sure confd is up and all interfaces have been brought up properly
    confdup = False
    while not confdup:
        confdInfo = waitSystemUp()
        if confdInfo == None:
            time.sleep(1)
            continue
        confdup = True
        confdInfo = str2json(confdInfo)

    #Remove any chutes from the restart queue if confd failed to bring up the
    #proper interfaces
    #
    # At this point, we only care about the chute names, not the full objects.
    # We are using sets of chute names for their O(1) membership test and
    # element uniqueness.
    okChutes = set([ch.name for ch in chutes])
    failedChutes = set()
    for iface in confdInfo:
        if iface.get('success') is False:
            failedChuteName = iface.get('comment')
            if failedChuteName == settings.RESERVED_CHUTE:
                out.warn('Failed to load a system config section')
            elif failedChuteName in okChutes:
                # This was a chute that we are supposed to restart, but one of
                # its config sections failed to load.
                okChutes.remove(failedChuteName)
                failedChutes.add(failedChuteName)
            elif failedChuteName not in failedChutes:
                # In this case, the name in the comment was not something that
                # we recognize from the chute storage.  Maybe the chute storage
                # file was deleted but not the config files, or someone
                # manually modified the config files.  Anyway, we cannot
                # attempt to stop this chute because the object does not exist,
                # but we can give a warning message.
                out.warn('Failed to load config section for '
                         'unrecognized chute: {}'.format(failedChuteName))

    #First stop all chutes that failed to bring up interfaces according to
    #pdconfd then start successful ones #We do this because pdfcd needs to
    #handle cleaning up uci files and then tell pdconfd
    updates = []
    for ch in failedChutes:
        updates.append(dict(updateClass='CHUTE', updateType='stop', name=ch,
                       tok=timeint(), func=updateStatus,
                       warning=FAILURE_WARNING))

    for ch in okChutes:
        updates.append(dict(updateClass='CHUTE', updateType='restart', name=ch,
                       tok=timeint(), func=updateStatus))

    return updates
def test_get_network_config():
    """
    Test generating network configuration for a chute update.
    """
    from paradrop.lib.config import network

    # Test interfaceDefsEqual function
    iface1 = {
        'name': 'mywifi',
        'netType': 'wifi',
        'internalIntf': 'wlan0'
    }
    iface2 = iface1.copy()
    assert network.interfaceDefsEqual(iface1, iface2)
    iface2['internalIntf'] = 'wlan1'
    assert not network.interfaceDefsEqual(iface1, iface2)

    # Test normal case where key is defined and encryption is implied.
    iface = dict()
    cfg = {'key': 'password'}
    network.getWifiKeySettings(cfg, iface)
    assert iface['key'] == "password"

    # Test normal case where encryption is set to "none".
    iface = dict()
    cfg = {'encryption': 'none'}
    network.getWifiKeySettings(cfg, iface)
    assert iface['encryption'] == "none"

    # Test error case where encryption is defined but no key is present.
    iface = dict()
    cfg = {'encryption': 'psk2'}
    assert_raises(Exception, network.getWifiKeySettings, cfg, iface)

    update = MockUpdate()
    update.old = None
    update.new = MockChute()

    # Should do nothing on a chute with no "networkInterfaces" cache key.
    network.reclaimNetworkResources(update.new)

    # Chute has no net information, we should pass silently.
    assert network.getNetworkConfig(update) is None

    update.new.net = {
        'mywifi': {
            'type': 'wifi',
            'intfName': 'wlan0',
            'encryption': 'psk2',
            'key': 'password'
        }
    }

    devices = {
        'wifi': [{'name': 'wlan0'}]
    }
    update.new.setCache("networkDevices", devices)

    # Missing 'ssid' field should raise exception.
    assert_raises(Exception, network.getNetworkConfig, update)

    update.new.net['mywifi']['ssid'] = "Paradrop"

    # Need to make a writable location for our config files.
    settings.UCI_CONFIG_DIR = tempfile.mkdtemp()

    # Try the normal sequence of steps for installing a new chute.
    network.getNetworkConfig(update)
    network.getOSNetworkConfig(update)
    network.getVirtNetworkConfig(update)
    network.setOSNetworkConfig(update)
    network.abortNetworkConfig(update)

    # Set up state so that old chute matches new chute.
    update.old = MockChute()
    update.old.net = update.new.net.copy()
    ifaces = list(update.new.getCache("networkInterfaces"))
    update.old.setCache("networkInterfaces", ifaces)

    # Now try sequence of steps that would occur for a restart.
    network.reclaimNetworkResources(update.old)
    network.getNetworkConfig(update)
    network.getOSNetworkConfig(update)
    network.getVirtNetworkConfig(update)
    network.setOSNetworkConfig(update)

    # Try asking for a new chute without any interfaces.
    update.new.net = dict()

    # This would be a restart where we remove an interface that was in old but
    # not in new.
    network.getNetworkConfig(update)
    network.getOSNetworkConfig(update)
    network.getVirtNetworkConfig(update)
    network.setOSNetworkConfig(update)
    network.abortNetworkConfig(update)

    # Try a network interface with missing 'type' field.
    update.new.net = {
        'mywifi': {
            'intfName': 'wlan0',
        }
    }
    assert_raises(Exception, network.getNetworkConfig, update)

    # Try asking for something funny.
    update.new.net = {
        'mywifi': {
            'type': 'fail',
            'intfName': 'wlan0',
        }
    }
    assert_raises(Exception, network.getNetworkConfig, update)

    # Clean up our config dir
    pdos.remove(settings.UCI_CONFIG_DIR)