Implement domain log watching
Implements the ability for a client to watch almost-live domain
console logs from the hypervisors. It does this using a deque-based
"tail -f" mechanism (with a configurable buffer per-VM) that watches
the domain console logfile in the (configurable) directory every
half-second. It then stores the current buffer in Zookeeper when
changed, where a client can then request it, either as a static piece
of text in the `less` pager, or via a similar "tail -f" functionality
implemented using fixed line splitting and comparison to provide a
generally-seamless output.
Enabling this feature requires each guest VM to implement a Libvirt
serial log and write its (text) console to it, for example using the
default logging directory:
```
<serial type='pty'>
<log file='/var/log/libvirt/vmname.log' append='off'/>
<serial>
```
The append mode can be either on or off; on grows files unbounded,
off causes the log (and hence the PVC log data) to be truncated on
initial VM startup from offline. The administrator must choose how
they best want to handle this until Libvirt implements their own
clog-type logging format.
This commit is contained in:
@@ -141,8 +141,10 @@ def readConfig(pvcd_config_file, myhostname):
|
||||
'enable_storage': o_config['pvc']['functions']['enable_storage'],
|
||||
'dynamic_directory': o_config['pvc']['system']['configuration']['directories']['dynamic_directory'],
|
||||
'log_directory': o_config['pvc']['system']['configuration']['directories']['log_directory'],
|
||||
'console_log_directory': o_config['pvc']['system']['configuration']['directories']['console_log_directory'],
|
||||
'file_logging': o_config['pvc']['system']['configuration']['logging']['file_logging'],
|
||||
'stdout_logging': o_config['pvc']['system']['configuration']['logging']['stdout_logging'],
|
||||
'console_log_lines': o_config['pvc']['system']['configuration']['logging']['console_log_lines'],
|
||||
'keepalive_interval': o_config['pvc']['system']['fencing']['intervals']['keepalive_interval'],
|
||||
'fence_intervals': o_config['pvc']['system']['fencing']['intervals']['fence_intervals'],
|
||||
'suicide_intervals': o_config['pvc']['system']['fencing']['intervals']['suicide_intervals'],
|
||||
@@ -457,12 +459,28 @@ zk_conn.add_listener(zk_listener)
|
||||
|
||||
# Cleanup function
|
||||
def cleanup():
|
||||
global zk_conn, update_timer
|
||||
logger.out('Terminating pvcd and cleaning up', state='s')
|
||||
|
||||
global zk_conn, update_timer, d_domains
|
||||
|
||||
# Stop keepalive thread
|
||||
stopKeepaliveTimer()
|
||||
try:
|
||||
stopKeepaliveTimer()
|
||||
except NameError:
|
||||
pass
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
logger.out('Terminating pvcd and cleaning up', state='s')
|
||||
# Stop console logging on all VMs
|
||||
logger.out('Stopping domain console watchers', state='s')
|
||||
for domain in d_domain:
|
||||
if d_domain[domain].getnode() == myhostname:
|
||||
try:
|
||||
d_domain[domain].console_log_instance.stop()
|
||||
except NameError as e:
|
||||
pass
|
||||
except AttributeError as e:
|
||||
pass
|
||||
|
||||
# Force into secondary network state if needed
|
||||
if zkhandler.readdata(zk_conn, '/nodes/{}/routerstate'.format(myhostname)) == 'primary':
|
||||
@@ -471,12 +489,7 @@ def cleanup():
|
||||
'/nodes/{}/routerstate'.format(myhostname): 'secondary',
|
||||
'/primary_node': 'none'
|
||||
})
|
||||
else:
|
||||
is_primary = False
|
||||
|
||||
# Wait for things to flush
|
||||
if is_primary:
|
||||
logger.out('Waiting for primary migration', state='s')
|
||||
logger.out('Waiting 3 seconds for primary migration', state='s')
|
||||
time.sleep(3)
|
||||
|
||||
# Set stop state in Zookeeper
|
||||
@@ -493,14 +506,11 @@ def cleanup():
|
||||
pass
|
||||
|
||||
logger.out('Terminated pvc daemon', state='s')
|
||||
|
||||
# Handle exit gracefully
|
||||
atexit.register(cleanup)
|
||||
sys.exit(0)
|
||||
|
||||
# Termination function
|
||||
def term(signum='', frame=''):
|
||||
# Exit
|
||||
sys.exit(0)
|
||||
cleanup()
|
||||
|
||||
# Handle signals gracefully
|
||||
signal.signal(signal.SIGTERM, term)
|
||||
|
||||
Reference in New Issue
Block a user