Deleting user with CMD_API_SELECT_USERS sometimes has empty result

kristian

Verified User
Joined
Nov 4, 2005
Messages
247
Location
Norway
In one of my scripts I delete users using the CMD_API_SELECT_USERS call (using the httpsocket.php library). Recently I've encountered a few situations where the deletion successfully completes with no special information in any DirectAdmin logs, but the result is empty.

Here's the function that does the deletion, with a print_r for debugging purposes:

PHP:
function deleteAccount($sock, $strUser) {
    $sock->set_method('POST');
    $sock->query('/CMD_API_SELECT_USERS',
        array(
            'confirmed' => 'Confirm',
            'delete' => 'yes',
            'select0' => $strUser,
        ));
    $resDeleteAccount = $sock->fetch_parsed_body();
    print_r($resDeleteAccount);
    if (isset($resDeleteAccount['error']) && $resDeleteAccount['error'] === '0') {
        printAndLog("Deletion of " . $strUser . " has been completed.\n");
    }
    else {
        printAndLog("There was a problem deleting the user " . $strUser . ": " . $resDeleteAccount['text'] . "\n");
        printAndLog("Details: " . $resDeleteAccount['details'] . "\n");
    }
}

The print_r shows this output:
PHP:
Array
(
)

I have not yet done any in depth debugging of this due to the fact that it's not really reproducible from what I can tell (it does not happen with all accounts). I was wondering if anyone had experienced similar issues and/or had any idea what might be causing this behaviour?
 

kristian

Verified User
Joined
Nov 4, 2005
Messages
247
Location
Norway
After several user deletions, I managed to trigger the error while having directadmin running in debug mode. Everything looks the same, except for this line:

Code:
File ./data/users/admin/users.list has been written to after this process read it.  Not going to overwrite it. This read timestamp=1621340435, before-write timestamp=1621340436

Here's the (almost) full output from ./directadmin b2000 from a normal deletion with a proper result returned:

Code:
Command::doCommand(/CMD_API_SELECT_USERS)
Command::delete_in_background: 1 accounts to be deleted in foreground: 52 <= 10240
Reseller::deleteUsers: Deleting account '<redacted-user>' ...
Tally::get_bandwidth_breakdown(ConfigFile &data, int cache=1, int year=0, int month=0): file=./data/users/<redacted-user>/bandwidth.tally.cache
IP::remove_list_from_domain_ips: should_add_domain_to_domainips=0
IP::add_list_to_helo_data: should_add_domain_to_domainips=0
Ftp::removeVirtualHost()
IP::removeFromIP(<redacted-ip>, skip_if_owned=0)
Database::set_mysqld_ver: got connection version: 10.2.23-MariaDB
Database::set_mysqld_ver: found vesion 10.2.23 mariadb=1
Database::clear_system_account_access_hosts(MYSQL &conf, db='<redacted-user>_forum'): query:
'DELETE FROM mysql.user                                                                         WHERE user='<redacted-user>' AND host NOT IN                                                                           (SELECT host FROM mysql.db WHERE (db!='<redacted-user>_forum' AND db!='<redacted-user>\_forum') AND (db LIKE '<redacted-user>_%' OR db LIKE '<redacted-user>\_%'))'
killUserProcess: non-zero response from killall process for '<redacted-user>' with exit code 1:
User::destroy: unlock_actions for <redacted-user>
User::destroy:<redacted-user>: DONE
User <redacted-user> removed by admin

Dynamic(api=1, error=0):
        text='Users deleted'
        result='User <redacted-user> Removed<br>
User removed from SSH<br>
<redacted-domain>'s config files have been removed<br>
<br>
Users's domains directory removed.<br>
<br>
Unix User removed from the server<br>
User's config files deleted<br>
User's data directory removed.<br>
Removed user from admin's list<br>
<br>
<br>
'
Command::doCommand(/CMD_API_SELECT_USERS) : finished
Command::run: finished /CMD_API_SELECT_USERS

The result returned and printed with the print_r mentioned earlier, was this:

Code:
Array                                                       
(                                                                   
    [error] => 0                                                                                   
    [text] => Users deleted                                                                       
    [details] => User <redacted-user> Removed<br>                             
User removed from SSH<br>                                   
<redacted-domain>'s config files have been removed<br>                                                 
<br>                                                                                             
Users's domains directory removed.<br>                                                   
<br>                                                       
Unix User removed from the server<br>                                                         
User's config files deleted<br>                                                   
User's data directory removed.<br>                                                                             
Removed user from admin's list<br>                                                                             
<br>                                                                                               
<br>                                                                 
                                                                                            
)

And this is the output from the API call that returned an empty result:

Code:
Command::doCommand(/CMD_API_SELECT_USERS)
Command::delete_in_background: 1 accounts to be deleted in foreground: 474 <= 10240
Reseller::deleteUsers: Deleting account '<redacted-user>' ...
Tally::get_bandwidth_breakdown(ConfigFile &data, int cache=1, int year=0, int month=0): file=./data/users/<redacted-user>/bandwidth.tally.cache
IP::remove_list_from_domain_ips: should_add_domain_to_domainips=0
IP::add_list_to_helo_data: should_add_domain_to_domainips=0
Ftp::removeVirtualHost()
IP::removeFromIP(<redacted-ip>, skip_if_owned=0)
Database::set_mysqld_ver: got connection version: 10.2.23-MariaDB
Database::set_mysqld_ver: found vesion 10.2.23 mariadb=1
killUserProcess: non-zero response from killall process for '<redacted-user>' with exit code 1:
User::destroy: unlock_actions for <redacted-user>
User::destroy:<redacted-user>: DONE
User <redacted-user> removed by admin

Dynamic(api=1, error=0):
        text='Users deleted'
        result='User <redacted-user> Removed<br>
User removed from SSH<br>
<redacted-domain>'s config files have been removed<br>
<br>
Users's domains directory removed.<br>
<br>
Unix User removed from the server<br>
User's config files deleted<br>
User's data directory removed.<br>
Removed user from admin's list<br>
<br>
<br>
'
Command::doCommand(/CMD_API_SELECT_USERS) : finished
File ./data/users/admin/users.list has been written to after this process read it.  Not going to overwrite it. This read timestamp=1621340435, before-write timestamp=1621340436
Command::run: finished /CMD_API_SELECT_USERS

That extra line in this output isn't reported as an error, so I'm not sure this is the cause, but it's the only difference I can see between the runs. Could there be some kind of bug here, causing the return value to be emptied?
 

kam

Verified User
Joined
Jan 4, 2009
Messages
54
You may want to test the API with postman for debugging.
 

kristian

Verified User
Joined
Nov 4, 2005
Messages
247
Location
Norway
Not sure I would get any more information from that, unless I've misunderstood what postman does. This looks like a bug inside DirectAdmin somewhere, handling the API call.
 

DirectAdmin Support

Administrator
Staff member
Joined
Feb 27, 2003
Messages
9,150
Looking in the httpsocket code, the fetch_parsed_body runs parse_str on the output.
If that function fails, the actual body might be there with "something", but still returning nothing.

For debug purposes, try echo'ing the call to
Code:
echo $sock->fetch_body()
which is the raw output, which may shed more info as to what's going on (or even $sock->fetch_result(), which is the entire output with headers... I believe)
 

kristian

Verified User
Joined
Nov 4, 2005
Messages
247
Location
Norway
Good point. I updated my deleteAccount() function to now print additional data:

PHP:
    $resDeleteAccount = $sock->fetch_parsed_body();
    print("\n\$resDeleteAccount (->fetch_parsed_body())\n");
    var_dump($resDeleteAccount);
    print("\n->get_status_code()\n");
    var_dump($sock->get_status_code());
    print("\n->fetch_result()\n");
    var_dump($sock->fetch_result());
    print("\n->fetch_header()\n");
    var_dump($sock->fetch_header());
    print("\n->fetch_body()\n");
    var_dump($sock->fetch_body());

This resulted in the following output for a failure situation:

Code:
$resDeleteAccount (->fetch_parsed_body())
array(0) {
}

->get_status_code()
int(200)

->fetch_result()
bool(false)

->fetch_header()
array(1) {
  [0]=>
  string(0) ""
}

->fetch_body()
bool(false)
 
Top