Exemplo n.º 1
0
    def test_get_station(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = [
            "Station 12:34:56:78:9a:bc (on wlan0)",
            "	inactive time:  304 ms",
            "	rx bytes:       18816",
            "	rx packets:     75",
            "	tx bytes:       5386",
            "	tx packets:     21",
            "	signal:         -29 dBm",
            "	tx bitrate:     54.0 MBit/s"
        ]

        request = MagicMock()
        request.user = User.get_internal_user()

        result = self.api.get_station(request, self.chute.name,
                self.interface['name'], '12:34:56:78:9a:bc')
        station = json.loads(result)
        assert station['mac_addr'] == '12:34:56:78:9a:bc'
        assert station['rx_bytes'] == '18816'
        assert station['signal'] == '-29 dBm'
        assert station['tx_bitrate'] == '54.0 MBit/s'
Exemplo n.º 2
0
def test_ChuteApi_get_chute(ChuteStorage, ChuteContainer):
    update_manager = MagicMock()
    api = chute_api.ChuteApi(update_manager)

    request = MagicMock()
    request.user = User.get_internal_user()

    container = MagicMock()
    container.getStatus.return_value = "running"
    ChuteContainer.return_value = container

    chute = MagicMock()
    chute.name = "test"
    chute.state = "running"
    chute.version = 5
    chute.environment = {}
    chute.resources = {}

    ChuteStorage.chuteList = {
        "test": chute
    }

    data = api.get_chute(request, chute.name)
    assert isinstance(data, basestring)

    result = json.loads(data)
    assert result['name'] == chute.name
    assert result['version'] == chute.version
Exemplo n.º 3
0
def test_ChuteApi_operations():
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    body = {
        'config': {}
    }

    request = MagicMock()
    request.content.read.return_value = json.dumps(body)
    request.user = User.get_internal_user()

    functions = [
        api.update_chute,
        api.stop_chute,
        api.start_chute,
        api.restart_chute,
        api.delete_chute
    ]
    for func in functions:
        print("Calling ChuteApi {}".format(func.__name__))

        data = func(request, "test")
        assert isinstance(data, basestring)

        result = json.loads(data)
        assert result['change_id'] == 1
Exemplo n.º 4
0
def test_ChuteApi_get_network(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    iface = {
        'name': 'vwlan0',
        'type': 'wifi',
        'internalIntf': 'wlan0'
    }

    chute = Chute(name="test")
    chute.setCache("networkInterfaces", [iface])

    ChuteStorage.chuteList = {
        "test": chute
    }

    request = MagicMock()
    request.user = User.get_internal_user()

    result = api.get_network(request, "test", "nomatch")
    assert result == "{}"

    result = api.get_network(request, "test", "vwlan0")
    data = json.loads(result)
    assert data['name'] == iface['name']
    assert data['type'] == iface['type']
    assert data['interface'] == iface['internalIntf']
Exemplo n.º 5
0
def test_ChuteApi_get_chute(ChuteStorage, ChuteContainer):
    update_manager = MagicMock()
    api = chute_api.ChuteApi(update_manager)

    request = MagicMock()
    request.user = User.get_internal_user()

    container = MagicMock()
    container.getStatus.return_value = "running"
    ChuteContainer.return_value = container

    chute = MagicMock()
    chute.name = "test"
    chute.version = 5
    chute.environment = {}
    chute.resources = {}

    ChuteStorage.chuteList = {"test": chute}

    data = api.get_chute(request, chute.name)
    assert isinstance(data, basestring)

    result = json.loads(data)
    assert result['name'] == chute.name
    assert result['version'] == chute.version
Exemplo n.º 6
0
    def _updates_received(self, response):
        if not response.success or response.data is None:
            print("There was an error receiving updates from the server.")
            return

        updates = response.data
        print("Received {} update(s) from server.".format(len(updates)))

        # Remove old updates from the set of in progress updates.  These are
        # updates that the server is no longer sending to us.
        received_set = set(item['_id'] for item in updates)
        old_updates = self.updates_in_progress - received_set
        self.updates_in_progress -= old_updates

        for item in updates:
            # TODO: Handle updates with started=True very carefully.
            #
            # There are at least two interesting cases:
            # 1. We started an update but crashed or rebooted without
            # completing it.
            # 2. We started an upgrade to paradrop, the daemon was just
            # restarted, but pdinstall has not reported that the update is
            # complete yet.
            #
            # If we skip updates with started=True, we will not retry updates
            # in case #1.
            if item['_id'] in self.updates_in_progress:
                continue
            elif item.get('started', False):
                yield self._update_ignored(item)
                continue
            else:
                self.updates_in_progress.add(item['_id'])

            creator = item.get('creator', {})
            username = creator.get("name", "paradrop")
            role = creator.get("access_level", "trusted")

            update = dict(updateClass=item['updateClass'],
                          updateType=item['updateType'],
                          user=User(username, "paradrop.org", role=role),
                          tok=timeint())

            # Save fields that relate to external management of this chute.
            update['external'] = {
                'update_id': item['_id'],
                'chute_id': item.get('chute_id', None),
                'version_id': item.get('version_id', None)
            }

            # Backend might send us garbage; be sure that we only accept the
            # config field if it is present and is a dict.
            config = item.get('config', {})
            if isinstance(config, dict):
                update.update(config)

            update = yield self.update_manager.add_update(**update)
            yield self._update_complete(update)
Exemplo n.º 7
0
    def test_hostapd_control(self, ChuteStorage, WebSocketResource):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        request = MagicMock()
        request.user = User.get_internal_user()

        self.api.hostapd_control(request, self.chute.name,
                                 self.interface['name'])
        WebSocketResource.assert_called()
Exemplo n.º 8
0
def get_access_level(user, node):
    access_rights = node.get('access_rights', [])

    roles = ["guest"]
    for item in access_rights:
        if item['user_id'] == user['_id']:
            roles.append(item['role'])

    return User.get_highest_role(roles)
Exemplo n.º 9
0
def get_access_level(user, node):
    access_rights = node.get('access_rights', [])

    roles = ["guest"]
    for item in access_rights:
        if item['user_id'] == user['_id']:
            roles.append(item['role'])

    return User.get_highest_role(roles)
Exemplo n.º 10
0
    def test_get_ssid(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {self.chute.name: self.chute}
        execute.return_value = "OK"

        request = MagicMock()
        request.user = User.get_internal_user()
        result = self.api.get_ssid(request, self.chute.name,
                                   self.interface['name'])
        assert result == "OK"
Exemplo n.º 11
0
    def test_set_chute_config(self, ChuteStorage):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        request = MagicMock()
        request.user = User.get_internal_user()

        result = self.api.set_chute_config(request, self.chute.name)
        change = json.loads(result)
        assert change['change_id'] == 1
Exemplo n.º 12
0
    def test_get_ssid(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }
        execute.return_value = "OK"

        request = MagicMock()
        request.user = User.get_internal_user()
        result = self.api.get_ssid(request, self.chute.name, self.interface['name'])
        assert result == "OK"
Exemplo n.º 13
0
    def test_hostapd_control(self, ChuteStorage, WebSocketResource):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }

        request = MagicMock()
        request.user = User.get_internal_user()

        self.api.hostapd_control(request, self.chute.name,
                self.interface['name'])
        WebSocketResource.assert_called()
Exemplo n.º 14
0
    def test_set_chute_config(self, ChuteStorage):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }

        request = MagicMock()
        request.user = User.get_internal_user()

        result = self.api.set_chute_config(request, self.chute.name)
        change = json.loads(result)
        assert change['change_id'] == 1
Exemplo n.º 15
0
def check_auth(request, password_manager, token_manager):
    auth_header = request.getHeader('Authorization')
    if auth_header is None:
        return False

    parts = auth_header.split()
    if parts[0] == "Basic":
        username, password = get_username_password(parts[1])
        request.user = User(username, "localhost", role="admin")
        return password_manager.verify_password(username, password)
    elif parts[0] == "Bearer":
        token = parts[1]

        # Chutes use non-expiring random tokens that are generated at container
        # creation. This works well because we do not want to deal with
        # expiration or revocation.
        allowed_tokens = get_allowed_bearer()
        if token in allowed_tokens:
            return True

        # Users (through the local portal or pdtools) can acquire expiring
        # JWTs. If the JWT decodes using our secret, then the caller is
        # authenticated.
        #
        # Later on, we may implement tokens issued by paradrop.org but
        # allowing user access to the router, etc. In that case we will
        # need to examine the subject, issuer, and audience claims.
        try:
            data = token_manager.decode(token)
            domain = data.get("domain", "localhost")
            username = data.get("sub", "paradrop")
            role = data.get("role", "user")
            request.user = User(username, domain, role=role)
            return True
        except token_manager.InvalidTokenError:
            pass

    return False
Exemplo n.º 16
0
    def test_get_leases(self, ChuteStorage):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        request = MagicMock()
        request.user = User.get_internal_user()

        with open("/tmp/dnsmasq-testing.leases", "w") as output:
            output.write("1512058246 00:0d:b9:40:30:80 10.42.0.213 * *")

        result = self.api.get_leases(request, "test", "testing")
        leases = json.loads(result)
        assert len(leases) == 1
        assert leases[0]['mac_addr'] == "00:0d:b9:40:30:80"
        assert leases[0]['ip_addr'] == "10.42.0.213"
Exemplo n.º 17
0
    def test_delete_station(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = ["OK"]

        request = MagicMock()
        request.user = User.get_internal_user()

        result = self.api.delete_station(request, self.chute.name,
                                         self.interface['name'],
                                         '12:34:56:78:9a:bc')
        messages = json.loads(result)
        assert len(messages) == 1
        assert messages[0] == "OK"
Exemplo n.º 18
0
    def test_get_leases(self, ChuteStorage):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }

        request = MagicMock()
        request.user = User.get_internal_user()

        with open("/tmp/dnsmasq-testing.leases", "w") as output:
            output.write("1512058246 00:0d:b9:40:30:80 10.42.0.213 * *")

        result = self.api.get_leases(request, "test", "testing")
        leases = json.loads(result)
        assert len(leases) == 1
        assert leases[0]['mac_addr'] == "00:0d:b9:40:30:80"
        assert leases[0]['ip_addr'] == "10.42.0.213"
Exemplo n.º 19
0
def test_ChuteApi_get_chute_cache(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    chute = MagicMock()
    chute.getCacheContents.return_value = {}

    ChuteStorage.chuteList = {"test": chute}

    request = MagicMock()
    request.user = User.get_internal_user()

    result = api.get_chute_cache(request, "test")
    assert result == "{}"
Exemplo n.º 20
0
def test_ChuteApi_get_chute_cache(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    chute = MagicMock()
    chute.getCacheContents.return_value = {}

    ChuteStorage.chuteList = {
        "test": chute
    }

    request = MagicMock()
    request.user = User.get_internal_user()

    result = api.get_chute_cache(request, "test")
    assert result == "{}"
Exemplo n.º 21
0
def test_ChuteApi_update_chute_tarfile(extract_tarred_chute):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    request = MagicMock()
    request.requestHeaders.getRawHeaders.return_value = ["application/x-tar"]
    request.user = User.get_internal_user()

    # Case 1: should work normally.
    workdir = "/tmp/test"
    paradrop_yaml = {
        'name': 'chute'
    }
    extract_tarred_chute.return_value = (workdir, paradrop_yaml)

    data = api.update_chute(request, "chute")
    assert isinstance(data, basestring)
    result = json.loads(data)
    assert result['change_id'] == 1
    assert update_manager.add_update.called

    # Case 2: deprecated way of declaring name, but should still work.
    workdir = "/tmp/test"
    paradrop_yaml = {
        'config': {
            'name': 'chute'
        }
    }
    extract_tarred_chute.return_value = (workdir, paradrop_yaml)

    data = api.update_chute(request, "chute")
    assert isinstance(data, basestring)
    result = json.loads(data)
    assert result['change_id'] == 1
    assert update_manager.add_update.called

    # Case 3: missing name, should raise exception.
    workdir = "/tmp/test"
    paradrop_yaml = {}
    extract_tarred_chute.return_value = (workdir, paradrop_yaml)

    assert_raises(Exception, api.update_chute, request, "chute")
Exemplo n.º 22
0
    def test_set_ssid(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {self.chute.name: self.chute}
        execute.return_value = "OK"

        request = MagicMock()
        request.user = User.get_internal_user()

        body = {}
        request.content.read.return_value = json.dumps(body)

        # Exception: ssid required
        assert_raises(Exception, self.api.set_ssid, request, "test", "testing")

        body = {'ssid': 'Free WiFi'}
        request.content.read.return_value = json.dumps(body)

        result = self.api.set_ssid(request, self.chute.name,
                                   self.interface['name'])
        assert result == "OK"
Exemplo n.º 23
0
    def test_delete_station(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = [
            "OK"
        ]

        request = MagicMock()
        request.user = User.get_internal_user()

        result = self.api.delete_station(request, self.chute.name,
                self.interface['name'], '12:34:56:78:9a:bc')
        messages = json.loads(result)
        assert len(messages) == 1
        assert messages[0] == "OK"
Exemplo n.º 24
0
def test_ChuteApi_get_networks(ChuteStorage):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    iface = {'name': 'vwlan0', 'type': 'wifi', 'internalIntf': 'wlan0'}

    chute = Chute(name="test")
    chute.setCache("networkInterfaces", [iface])

    ChuteStorage.chuteList = {"test": chute}

    request = MagicMock()
    request.user = User.get_internal_user()

    result = api.get_networks(request, "test")
    data = json.loads(result)
    assert len(data) == 1
    assert data[0]['name'] == iface['name']
    assert data[0]['type'] == iface['type']
    assert data[0]['interface'] == iface['internalIntf']
Exemplo n.º 25
0
    def test_set_ssid(self, ChuteStorage, execute):
        ChuteStorage.chuteList = {
            self.chute.name: self.chute
        }
        execute.return_value = "OK"

        request = MagicMock()
        request.user = User.get_internal_user()

        body = {}
        request.content.read.return_value = json.dumps(body)

        # Exception: ssid required
        assert_raises(Exception, self.api.set_ssid, request, "test", "testing")

        body = {
            'ssid': 'Free WiFi'
        }
        request.content.read.return_value = json.dumps(body)

        result = self.api.set_ssid(request, self.chute.name, self.interface['name'])
        assert result == "OK"
Exemplo n.º 26
0
def test_ChuteApi_update_chute_tarfile(extract_tarred_chute):
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    request = MagicMock()
    request.requestHeaders.getRawHeaders.return_value = ["application/x-tar"]
    request.user = User.get_internal_user()

    # Case 1: should work normally.
    workdir = "/tmp/test"
    paradrop_yaml = {'name': 'chute'}
    extract_tarred_chute.return_value = (workdir, paradrop_yaml)

    data = api.update_chute(request, "chute")
    assert isinstance(data, basestring)
    result = json.loads(data)
    assert result['change_id'] == 1
    assert update_manager.add_update.called

    # Case 2: deprecated way of declaring name, but should still work.
    workdir = "/tmp/test"
    paradrop_yaml = {'config': {'name': 'chute'}}
    extract_tarred_chute.return_value = (workdir, paradrop_yaml)

    data = api.update_chute(request, "chute")
    assert isinstance(data, basestring)
    result = json.loads(data)
    assert result['change_id'] == 1
    assert update_manager.add_update.called

    # Case 3: missing name, should raise exception.
    workdir = "/tmp/test"
    paradrop_yaml = {}
    extract_tarred_chute.return_value = (workdir, paradrop_yaml)

    assert_raises(Exception, api.update_chute, request, "chute")
Exemplo n.º 27
0
    def test_get_station(self, ChuteStorage, Popen):
        ChuteStorage.chuteList = {self.chute.name: self.chute}

        proc = MagicMock()
        Popen.return_value = proc
        proc.stdout = [
            "Station 12:34:56:78:9a:bc (on wlan0)", "	inactive time:  304 ms",
            "	rx bytes:       18816", "	rx packets:     75",
            "	tx bytes:       5386", "	tx packets:     21",
            "	signal:         -29 dBm", "	tx bitrate:     54.0 MBit/s"
        ]

        request = MagicMock()
        request.user = User.get_internal_user()

        result = self.api.get_station(request, self.chute.name,
                                      self.interface['name'],
                                      '12:34:56:78:9a:bc')
        station = json.loads(result)
        assert station['mac_addr'] == '12:34:56:78:9a:bc'
        assert station['rx_bytes'] == '18816'
        assert station['signal'] == '-29 dBm'
        assert station['tx_bitrate'] == '54.0 MBit/s'
Exemplo n.º 28
0
def test_ChuteApi_operations():
    update_manager = MagicMock()
    update_manager.assign_change_id.return_value = 1

    api = chute_api.ChuteApi(update_manager)

    body = {'config': {}}

    request = MagicMock()
    request.content.read.return_value = json.dumps(body)
    request.user = User.get_internal_user()

    functions = [
        api.update_chute, api.stop_chute, api.start_chute, api.restart_chute,
        api.delete_chute
    ]
    for func in functions:
        print("Calling ChuteApi {}".format(func.__name__))

        data = func(request, "test")
        assert isinstance(data, basestring)

        result = json.loads(data)
        assert result['change_id'] == 1
Exemplo n.º 29
0
def reloadChutes():
    """
    Get update objects to chutes that should be running at startup.

    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.

    :returns: (list) A list of UpdateChute objects that should be run
              before accepting new updates.
    """
    if not settings.PDCONFD_ENABLED:
        return []
    chuteStore = ChuteStorage()
    chutes = [ch for ch in chuteStore.getChuteList() if ch.isRunning()]

    # 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 = json.loads(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 == constants.RESERVED_CHUTE_NAME:
                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))

    updates = []

    # There was code here that looped over the failedChutes set and explicitly
    # stopped those chutes.  However, if the cause of the failure was
    # transient, those chutes would remain stopped until manually restarted.
    # It seems better to leave them alone so that we try again next time the
    # system reboots.
    #
    # TODO: We should still record the failure somewhere.

    # Only try to restart the chutes that had no problems during pdconf
    # initialization.
    for ch in okChutes:
        update_spec = dict(updateClass='CHUTE',
                           updateType='restart',
                           name=ch,
                           tok=timeint(),
                           func=updateStatus,
                           user=User.get_internal_user())
        update = UpdateChute(update_spec, reuse_existing=True)
        updates.append(update)

    return updates
Exemplo n.º 30
0
def reloadChutes():
    """
    Get update objects to chutes that should be running at startup.

    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.

    :returns: (list) A list of UpdateChute objects that should be run
              before accepting new updates.
    """
    if not settings.PDCONFD_ENABLED:
        return []
    chuteStore = ChuteStorage()
    chutes = [ ch for ch in chuteStore.getChuteList() if ch.isRunning() ]

    # 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 = json.loads(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 == constants.RESERVED_CHUTE_NAME:
                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))

    updates = []

    # There was code here that looped over the failedChutes set and explicitly
    # stopped those chutes.  However, if the cause of the failure was
    # transient, those chutes would remain stopped until manually restarted.
    # It seems better to leave them alone so that we try again next time the
    # system reboots.
    #
    # TODO: We should still record the failure somewhere.

    # Only try to restart the chutes that had no problems during pdconf
    # initialization.
    for ch in okChutes:
        update_spec = dict(updateClass='CHUTE', updateType='restart', name=ch,
                tok=timeint(), func=updateStatus,
                user=User.get_internal_user())
        update = UpdateChute(update_spec, reuse_existing=True)
        updates.append(update)

    return updates