Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option to libvirtkvm collector to build instance name based on openstack metadata #481

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions docs/collectors/LibvirtKVMCollector.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,17 @@ Uses libvirt to harvest per KVM instance stats
Setting | Default | Description | Type
--------|---------|-------------|-----
byte_unit | byte | Default numeric output(s) | str
cpu_absolute | False | CPU stats reported as percentage by default, or<br>
as cummulative nanoseconds since VM creation if this is True. | bool
cpu_absolute | False | CPU stats reported as percentage by default, or as cummulative nanoseconds since VM creation if this is True. | bool
enabled | False | Enable collecting these metrics | bool
measure_collector_time | False | Collect the collector run time in ms | bool
metrics_blacklist | None | Regex to match metrics to block. Mutually exclusive with metrics_whitelist | NoneType
metrics_whitelist | None | Regex to match metrics to transmit. Mutually exclusive with metrics_blacklist | NoneType
sort_by_uuid | False | Use the <uuid> of the instance instead of the<br>
default <name>, useful in Openstack deploments where <name> is only<br>
specific to the compute node | bool
uri | qemu:///system | The libvirt connection URI. By default it's<br>
'qemu:///system'. One decent option is<br>
'qemu+unix:///system?socket=/var/run/libvirt/libvit-sock-ro'. | str
sort_by_uuid | False | Use the <uuid> of the instance instead of the default <name>, useful in Openstack deploments where <name> is only specific to the compute node | bool
uri | qemu:///system | The libvirt connection URI. By default it's 'qemu:///system'. One decent option is 'qemu+unix:///system?socket=/var/run/libvirt/libvit-sock-ro'. | str
format_name_using_metadata | False | Use openstack metadata to generate instance name, its useful when do you and to group VMs metrics by project. Available values: ${owner_project},${owner_project_uuid},${instance},${instance_uuid} | list

#### Example Output

```
__EXAMPLESHERE__
```

54 changes: 54 additions & 0 deletions src/collectors/libvirtkvm/libvirtkvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

import diamond.collector
from diamond.collector import str_to_bool

from string import Template

try:
from xml.etree import ElementTree
except ImportError:
Expand Down Expand Up @@ -41,6 +44,43 @@ class LibvirtKVMCollector(diamond.collector.Collector):
'tx_drops': 7
}

def format_name_using_metadata(self, dom, format):
s = Template(format)

tree = ElementTree.fromstring(
dom.metadata(2,
"http://openstack.org/xmlns/libvirt/nova/1.0"))

for target in tree.findall('name'):
instance = target.text

instance_uuid = dom.UUIDString()

for target in tree.findall('owner/project'):
owner_project_uuid = target.get("uuid")
owner_project = target.text

for target in tree.findall('owner/user'):
owner_user_uuid = target.get("uuid")
owner_user = target.text

instance = instance.replace(".", "_")
owner_project = owner_project.replace(".", "_")
owner_user = owner_user.replace(".", "_")

params = {'owner_project': owner_project,
'owner_project_uuid': owner_project_uuid,
'owner_user': owner_user,
'owner_user_uuid': owner_user_uuid,
'instance': instance,
'instance_uuid': instance_uuid}

try:
return s.substitute(params)
except KeyError as err:
self.log.error('invalid format parameter %s' % err)
return instance

def get_default_config_help(self):
config_help = super(LibvirtKVMCollector,
self).get_default_config_help()
Expand Down Expand Up @@ -104,10 +144,24 @@ def collect(self):
self.log.error('Unable to import libvirt')
return {}

self.log.debug('Connecting to %s' % self.config['uri'])

conn = libvirt.openReadOnly(self.config['uri'])

if conn is None:
self.log.error('Failed to open connection to the hypervisor on %s' %
self.config['uri'])
return {}

for dom in [conn.lookupByID(n) for n in conn.listDomainsID()]:
if str_to_bool(self.config['sort_by_uuid']):
name = dom.UUIDString()

elif self.config['format_name_using_metadata']:
name = self.format_name_using_metadata(
dom,
self.config['format_name_using_metadata'])

else:
name = dom.name()

Expand Down
Empty file.
44 changes: 43 additions & 1 deletion src/collectors/libvirtkvm/test/testlibvirtkvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
from test import CollectorTestCase
from test import get_collector_config
from test import unittest
from mock import Mock
from mock import patch

from libvirtkvm import LibvirtKVMCollector


###############################################################################

class TestLibvirtKVMCollector(CollectorTestCase):
Expand All @@ -21,6 +22,47 @@ def setUp(self):
def test_import(self):
self.assertTrue(LibvirtKVMCollector)

@patch('libvirt')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone can help here ? I need to mock the entire libvirt module...

I'm not a python guy and had never written this kind of tests 💥

@patch.object(Collector, 'publish')

def test_should_work_with_real_data(self, publish_mock, libvirt_mock):
libvirt = Mock()
conn_mock = Mock()
dom_mock = Mock()

listDomainsID = [ 1 ]

libvirt_mock.return_value = libvirt
libvirt.openReadOnly.return_value = conn_mock
conn_mock.listDomainsID.return_value = listDomainsID
conn_mock.lookupByID.return_value = dom_mock

dom_mock.UUIDString.return_value = "uuid"

dom_mock.getCPUStats.return_value = [{'cpu_time': 30375130070L,
'system_time': 6980000000L,
'user_time': 3120000000L}]

self.collector.collect()

metrics = {
'MemTotal': 49554212,
'MemFree': 35194496,
'Buffers': 1526304,
'Cached': 10726736,
'Active': 10022168,
'Dirty': 24748,
'Inactive': 2524928,
'Shmem': 276,
'SwapTotal': 262143996,
'SwapFree': 262143996,
'SwapCached': 0,
'VmallocTotal': 34359738367,
'VmallocUsed': 445452,
'VmallocChunk': 34311049240
}


###############################################################################
if __name__ == "__main__":
unittest.main()