Cleanup keystone tokens

Every once in a while you really want to cleanup the token table of the Keystone database. A couple of weeks ago while backuping my cloud controller I noticed that the backup of the Keystone database was longer than the other databases. After that, I checked the size of the dump (compressed) 60MB. Hummm but there is almost nothing in the Keystone database: users, tenants… wait.. could it be TOKENS?!

The token validity is manage via the following options in keystone.conf:

driver = keystone.token.backends.sql.Token

# Amount of time a token should remain valid (in seconds)
expiration = 86400

One option could be to use different backend to store the tokens:

  • The keystone.token.backends.memcache, Memcached storage backend
  • The keystone.token.backends.kvs, Key Value storage backend

I will prefer another backend to store the tokens in order to make database dump shorter and smaller. I’m not quite sure if memcache is a good candidat though. This could make things harder for some reasons like:

  • Does the token remain forever in memcache?
  • Cache consistency, if a server crash
  • Makes the setup more complex, try to achieve a replicated memcache

See this launchpad discussion for more details.

Every nova/glance/cinder commands ask for a token while trying to execute a command.

I personnally end up with the following:

$ sudo mysql -uroot -p -e 'USE keystone; SELECT * FROM token;' | wc -l
Enter password:

The setup runs for 2 months now and already 1970938 and I don’t run a public cloud. I can’t imagine the nightmare with a public cloud…

Little bash script:



mysql -u${mysql_user} -p${mysql_password} -h${mysql_host} -e 'USE keystone ; DELETE FROM token WHERE NOT DATE_SUB(CURDATE(),INTERVAL 2 DAY) <= expires;'

If during the process you endup with this error:

ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction

Simply increase the innodb_lock_wait_timeout:

mysql> show variables like 'innodb_lock_wait_timeout';
| Variable_name | Value |
| innodb_lock_wait_timeout | 50 |
1 row in set (0.00 sec)

mysql> set innodb_lock_wait_timeout=100;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
| Variable_name | Value |
| innodb_lock_wait_timeout | 100 |

Then re-run your command again.

Note: I volontary let a retention of 2 days in the command since I work with days and not with hours. It’s not always day per day, thus some token could overlap and be valid. So 2 days are fine.

II. Bonus

II.1. Retrieve a token with curl

If you want to retrieve a token via curl:

$ curl -s -d "{\"auth\":{\"passwordCredentials\": {\"username\": \"admin\", \"password\": \"admin\"}, \"tenantName\": \"admin\"}}" -H "Content-type: application/json" | tr ',' 'n' | grep '"id":' | cut -d'"' -f12 | head --lines 1

II.2. Cron task for the cleanup script

Script to execute periodically:


# Purpose of the script
# Everytime a service wants to be do 'something' it has to retrieve an autentication token
# Nova/Glance/Cinder services are manage by Pacemaker and monitor functions (from the RA) ask for a token every 10 sec
# There is no cleanup procedure nor periodical task running to delete expire token

mysql=$(which mysql)

logger -t keystone-cleaner "Starting Keystone 'token' table cleanup"

logger -t keystone-cleaner "Starting token cleanup"
mysql -u${mysql_user} -p${mysql_password} -h${mysql_host} -e 'USE keystone ; DELETE FROM token WHERE NOT DATE_SUB(CURDATE(),INTERVAL 2 DAY) <= expires;'
valid_token=$($mysql -u${mysql_user} -p${mysql_password} -h${mysql_host} -e 'USE keystone ; SELECT * FROM token;' | wc -l)
logger -t keystone-cleaner "Finishing token cleanup, there is still $valid_token valid tokens..."

exit 0

II.3. Use memcached to store Keystone tokens

Install memcached:

$ sudo apt-get install memcached -y

Put the following option in your keystone.conf:

driver = keystone.token.backends.memcache.Token

Then restart the service Keystone:

$ sudo service keystone restart

Check if the connection is well established:

$ sudo lsof -i :11211
memcached 2900 memcache 26u IPv4 20295625 0t0 TCP localhost:11211 (LISTEN)
memcached 2900 memcache 27u IPv4 20295626 0t0 UDP localhost:11211
memcached 2900 memcache 29u IPv4 20307867 0t0 TCP localhost:11211->localhost:37623 (ESTABLISHED)
memcached 2900 memcache 30u IPv4 20307869 0t0 TCP localhost:11211->localhost:37626 (ESTABLISHED)
memcached 2900 memcache 31u IPv4 20307925 0t0 TCP localhost:11211->localhost:37634 (ESTABLISHED)
keystone- 10599 keystone 10u IPv4 20308147 0t0 TCP localhost:37623->localhost:11211 (ESTABLISHED)
keystone- 10599 keystone 13u IPv4 20308153 0t0 TCP localhost:37626->localhost:11211 (ESTABLISHED)
keystone- 10599 keystone 15u IPv4 20308221 0t0 TCP localhost:37634->localhost:11211 (ESTABLISHED)

Retrieve cache object count:

$ sudo telnet 11211
Connected to
Escape character is '^]'.
stats items
STAT items:9:number 4
STAT items:9:age 314
STAT items:9:evicted 0
STAT items:9:evicted_nonzero 0
STAT items:9:evicted_time 0
STAT items:9:outofmemory 0
STAT items:9:tailrepairs 0
STAT items:9:reclaimed 0
STAT items:9:expired_unfetched 0
STAT items:9:evicted_unfetched 0
STAT items:10:number 1310
STAT items:10:age 511
STAT items:10:evicted 0
STAT items:10:evicted_nonzero 0
STAT items:10:evicted_time 0
STAT items:10:outofmemory 0
STAT items:10:tailrepairs 0
STAT items:10:reclaimed 0
STAT items:10:expired_unfetched 0
STAT items:10:evicted_unfetched 0
Connection closed by foreign host.

You should see the STAT items:10:number growing and growing.

Simply run the script aaaaaannnd it’s gone!