Status API: Return live hosts and services

Change-Id: I97ccadfa06387924a368a5ac2fb27ba374b7f03f
This commit is contained in:
aviau 2015-04-16 18:08:51 -04:00
parent 26efcedf6b
commit fa47ae8302
23 changed files with 696 additions and 36 deletions

View File

@ -17,7 +17,7 @@ Hosts
.. rest-controller:: surveil.api.controllers.v2.status.hosts:HostController
:webprefix: /v2/status/hosts/
.. rest-controller:: surveil.api.controllers.v2.status.hosts.config:ConfigController
.. rest-controller:: surveil.api.controllers.v2.status.hosts:ConfigController
:webprefix: /v2/status/hosts/(host_name)/config
.. rest-controller:: surveil.api.controllers.v2.status.metrics:MetricsController
@ -38,6 +38,13 @@ Hosts
.. rest-controller:: surveil.api.controllers.v2.logs.notifications:NotificationsController
:webprefix: /v2/status/hosts/(host_name)/events/notifications
Services
========
.. rest-controller:: surveil.api.controllers.v2.status.services:ServicesController
:webprefix: /v2/status/services
Metrics
=======
@ -45,4 +52,16 @@ Metrics
:webprefix: /v2/status/metrics
.. rest-controller:: surveil.api.controllers.v2.status.metrics:MetricController
:webprefix: /v2/status/metrics/
:webprefix: /v2/status/metrics/
Types
=====
.. autotype:: surveil.api.datamodel.status.live_service.LiveService
:members:
.. autotype:: surveil.api.datamodel.status.live_host.LiveHost
:members:
.. autotype:: surveil.api.datamodel.status.live_query.LiveQuery
:members:

View File

@ -8,3 +8,4 @@ oslo.middleware
oslo.policy>=0.3.0
keystonemiddleware
PasteDeploy
influxdb==2.0.1

View File

@ -26,13 +26,15 @@ server = {
# as long as is it in the same format.
surveil_api_config = {
"mongodb_uri": "mongodb://mongo:27017",
"ws_arbiter_url": "http://shinken:7760"
"ws_arbiter_url": "http://shinken:7760",
"influxdb_uri": "influxdb://root:root@influxdb:8086/db"
}
app_hooks = [
hooks.DBHook(
surveil_api_config['mongodb_uri'],
surveil_api_config['ws_arbiter_url']
surveil_api_config['ws_arbiter_url'],
surveil_api_config['influxdb_uri']
)
]

View File

@ -16,10 +16,11 @@ from pecan import rest
from surveil.api.controllers.v2.status import hosts as v2_hosts
from surveil.api.controllers.v2.status import metrics
from surveil.api.controllers.v2.status import services as v2_services
class StatusController(rest.RestController):
# events = EventsController()
hosts = v2_hosts.HostsController()
# services = ServicesController()
services = v2_services.ServicesController()
metrics = metrics.MetricsController()

View File

@ -14,18 +14,30 @@
import pecan
from pecan import rest
import wsmeext.pecan as wsme_pecan
from surveil.api.controllers.v2 import logs
from surveil.api.controllers.v2.status.hosts import config
from surveil.api.controllers.v2.status import metrics
from surveil.api.datamodel.status import live_host
from surveil.api.datamodel.status import live_query
from surveil.api.handlers.status import live_host_handler
class HostsController(rest.RestController):
@pecan.expose()
@wsme_pecan.wsexpose([live_host.LiveHost])
def get_all(self):
"""Returns all hosts."""
return "ALLL HOSSSSSSSST"
handler = live_host_handler.HostHandler(pecan.request)
hosts = handler.get_all()
return hosts
@wsme_pecan.wsexpose([live_host.LiveHost], body=live_query.LiveQuery)
def post(self, query):
"""Given a LiveQuery, returns all matching hosts."""
handler = live_host_handler.HostHandler(pecan.request)
hosts = handler.get_all(live_query=query)
return hosts
@pecan.expose()
def _lookup(self, host_name, *remainder):
@ -37,7 +49,7 @@ class HostController(rest.RestController):
# services = ServicesController()
# See init for controller creation. We need host_name to instanciate it
# externalcommands = ExternalCommandsController()
config = config.ConfigController()
# config = config.ConfigController()
events = logs.LogsController()
metrics = metrics.MetricsController()
@ -52,3 +64,11 @@ class HostController(rest.RestController):
output = '{"host_name": "myhostname", "alias": %s}' % self._id
return output
class ConfigController(rest.RestController):
@pecan.expose()
def get_all(self):
"""Returns config from a specific host."""
return "Dump CONFIG"

View File

@ -1,24 +0,0 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import pecan
from pecan import rest
class ConfigController(rest.RestController):
@pecan.expose()
def get_all(self):
"""Returns config from a specific host."""
return "Dump CONFIG"

View File

@ -0,0 +1,38 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import pecan
from pecan import rest
import wsmeext.pecan as wsme_pecan
from surveil.api.datamodel.status import live_query
from surveil.api.datamodel.status import live_service
from surveil.api.handlers.status import live_service_handler
class ServicesController(rest.RestController):
@wsme_pecan.wsexpose([live_service.LiveService])
def get_all(self):
"""Returns all services."""
handler = live_service_handler.ServiceHandler(pecan.request)
services = handler.get_all()
return services
@wsme_pecan.wsexpose([live_service.LiveService], body=live_query.LiveQuery)
def post(self, query):
"""Given a LiveQuery, returns all matching services."""
handler = live_service_handler.ServiceHandler(pecan.request)
services = handler.get_all(live_query=query)
return services

View File

View File

@ -0,0 +1,49 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import wsme
import wsme.types as wtypes
from surveil.api.controllers.v1.datamodel import types
class LiveHost(types.Base):
host_name = wsme.wsattr(wtypes.text, mandatory=False)
"""The name of the host"""
description = wsme.wsattr(wtypes.text, mandatory=False)
"""The description of the host"""
state = wsme.wsattr(int, mandatory=False)
"""The current state of the host"""
last_check = wsme.wsattr(int, mandatory=False)
"""The last time the host was checked"""
last_state_change = wsme.wsattr(int, mandatory=False)
"""The last time the state has changed"""
plugin_output = wsme.wsattr(wtypes.text, mandatory=False)
"""Plugin output of the last check"""
@classmethod
def sample(cls):
return cls(
host_name='CoolHost',
description='Very Nice Host',
state=0,
last_check=1429220785,
last_state_change=1429220785,
plugin_output='PING OK - Packet loss = 0%, RTA = 0.02 ms'
)

View File

@ -0,0 +1,42 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import wsme
import wsme.types as wtypes
from surveil.api.controllers.v1.datamodel import types
class LiveQuery(types.Base):
"""Holds a sample query encoded in json."""
filters = wsme.wsattr(wtypes.text, mandatory=True)
"The filter expression encoded in json."
fields = wsme.wsattr(wtypes.text, mandatory=True)
"List of fields to include in the response."
@classmethod
def sample(cls):
return cls(
fields=json.dumps(['host_name', 'last_check']),
filters=json.dumps({
"isnot": {
"state": ["0", "1"],
"host_state": ["2"]
}
})
)

View File

@ -0,0 +1,53 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import wsme
import wsme.types as wtypes
from surveil.api.controllers.v1.datamodel import types
class LiveService(types.Base):
host_name = wsme.wsattr(wtypes.text, mandatory=False)
"""The host for the service"""
service_description = wsme.wsattr(wtypes.text, mandatory=False)
"""The name of the service"""
description = wsme.wsattr(wtypes.text, mandatory=False)
"""The description of the sevice"""
state = wsme.wsattr(int, mandatory=False)
"""The current state of the service"""
last_check = wsme.wsattr(int, mandatory=False)
"""The last time the service was checked"""
last_state_change = wsme.wsattr(int, mandatory=False)
"""The last time the state has changed"""
plugin_output = wsme.wsattr(wtypes.text, mandatory=False)
"""Plugin output of the last check"""
@classmethod
def sample(cls):
return cls(
host_name='Webserver',
service_name='Apache',
description='Serves Stuff',
state=0,
last_check=1429220785,
last_state_change=1429220785,
plugin_output='HTTP OK - GOT NICE RESPONSE'
)

View File

View File

@ -0,0 +1,52 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
def filter_dict_list_with_live_query(item_list, live_query):
filters = json.loads(live_query.filters)
matching_items = []
for item in item_list:
matches = True
# Filters are, for example, 'isnot' or 'is'
for filter in filters.items():
# Fields are, for example, 'STATE'
for field in filter[1].items():
# Values are, for example, 0, 1, UP, Down...
for value in field[1]:
if filter[0] == "isnot":
if item[field[0]] == value:
matches = False
break
elif filter[0] == "is":
if item[field[0]] != value:
matches = False
break
if matches:
fields = json.loads(live_query.fields)
matching_item = {}
for field in fields:
matching_item[field] = item[field]
matching_items.append(matching_item)
return matching_items

View File

@ -0,0 +1,58 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
from surveil.api.datamodel.status import live_host
from surveil.api.handlers import handler
from surveil.api.handlers.status import liveQuery_filter as query_filter
class HostHandler(handler.Handler):
"""Fulfills a request on the live hosts."""
def get_all(self, live_query=None):
"""Return all live hosts."""
cli = self.request.influxdb_client
query = "SELECT * from HOST_STATE GROUP BY host_name LIMIT 1"
response = cli.query(query)
host_dicts = []
for item in response.items():
first_entry = next(item[1])
host_dict = {
"host_name": item[0][1]['host_name'],
"description": item[0][1]['host_name'],
"state": first_entry['state'],
"last_check": int(first_entry['last_check']),
"last_state_change": int(first_entry['last_state_change']),
"plugin_output": first_entry['output']
}
host_dicts.append(host_dict)
if live_query:
host_dicts = query_filter.filter_dict_list_with_live_query(
host_dicts,
live_query
)
hosts = []
for host_dict in host_dicts:
host = live_host.LiveHost(**host_dict)
hosts.append(host)
return hosts

View File

@ -0,0 +1,64 @@
# Copyright 2014 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
from surveil.api.datamodel.status import live_service
from surveil.api.handlers import handler
from surveil.api.handlers.status import liveQuery_filter as query_filter
class ServiceHandler(handler.Handler):
"""Fulfills a request on live services."""
def get_all(self, live_query=None):
"""Return all live services."""
cli = self.request.influxdb_client
query = (
"SELECT * from SERVICE_STATE "
"GROUP BY host_name, service_description "
"LIMIT 1"
)
response = cli.query(query)
service_dicts = []
for item in response.items():
first_entry = next(item[1])
service_dict = {
"service_description": item[0][1]['service_description'],
"host_name": item[0][1]['host_name'],
"description": item[0][1]['service_description'],
"state": first_entry['state'],
"last_check": int(first_entry['last_check']),
"last_state_change": int(first_entry['last_state_change']),
"plugin_output": first_entry['output']
}
service_dicts.append(service_dict)
if live_query:
service_dicts = query_filter.filter_dict_list_with_live_query(
service_dicts,
live_query
)
services = []
for service_dict in service_dicts:
service = live_service.LiveService(**service_dict)
services.append(service)
return services

View File

@ -12,21 +12,26 @@
# License for the specific language governing permissions and limitations
# under the License.
import influxdb
from pecan import hooks
import pymongo
class DBHook(hooks.PecanHook):
def __init__(self, mongo_url, ws_arbiter_url):
def __init__(self, mongo_url, ws_arbiter_url, influxdb_url):
self.mongo_url = mongo_url
self.ws_arbiter_url = ws_arbiter_url
self.influxdb_url = influxdb_url
def before(self, state):
self.mongoclient = pymongo.MongoClient(self.mongo_url)
state.request.mongo_connection = self.mongoclient
state.request.ws_arbiter_url = self.ws_arbiter_url
state.request.influxdb_client = influxdb.InfluxDBClient.from_DSN(
self.influxdb_url
)
def after(self, state):
self.mongoclient.close()

View File

@ -0,0 +1,93 @@
# Copyright 2015 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import httpretty
from surveil.tests.api import functionalTest
class TestStatusHosts(functionalTest.FunctionalTest):
def setUp(self):
super(TestStatusHosts, self).setUp()
self.influxdb_response = (
'{"results":[{"series":[{"name":"HOST_STATE","tags":{"host_nam'
'e":"localhost"},"columns":["time","last_check","last_state_chan'
'ge","output","state","state_type"],"values":[["201'
'5-04-19T01:09:24Z",1.429405764e+09,1.429405765316929e+09,"OK '
'- localhost: rta 0.033ms, lost 0%",0,"HARD"]]},{"name":"'
'HOST_STATE","tags":{"host_name":"test_keystone"},"columns":["'
'time","last_check","last_state_change","output","state",'
'"state_type"],"values":[["2015-04-19T01:09:23Z",1.4294057'
'63e+09,1.429405765317144e+09,"OK - 127.0.0.1: rta 0.032ms, lo'
'st 0%",0,"HARD"]]},{"name":"HOST_STATE","tags":{"host_na'
'me":"ws-arbiter"},"columns":["time","last_check","last_state_ch'
'ange","output","state","state_type"],"values":[["2'
'015-04-19T01:09:24Z",1.429405764e+09,1.429405765317063e+09,"O'
'K - localhost: rta 0.030ms, lost 0%",0,"HARD"]]}]}]}'
)
@httpretty.activate
def test_get_all_hosts(self):
httpretty.register_uri(httpretty.GET,
"http://influxdb:8086/query",
body=self.influxdb_response)
response = self.app.get("/v2/status/hosts")
expected = [
{"description": "localhost",
"last_state_change": 1429405765,
"plugin_output": "OK - localhost: rta 0.033ms, lost 0%",
"last_check": 1429405764,
"state": 0,
"host_name": "localhost"},
{"description": "test_keystone",
"last_state_change": 1429405765,
"plugin_output": "OK - 127.0.0.1: rta 0.032ms, lost 0%",
"last_check": 1429405763,
"state": 0,
"host_name": "test_keystone"},
{"description": "ws-arbiter",
"last_state_change": 1429405765,
"plugin_output": "OK - localhost: rta 0.030ms, lost 0%",
"last_check": 1429405764,
"state": 0,
"host_name": "ws-arbiter"}]
self.assertEqual(json.loads(response.body), expected)
@httpretty.activate
def test_query_hosts(self):
httpretty.register_uri(httpretty.GET,
"http://influxdb:8086/query",
body=self.influxdb_response)
query = {
'fields': json.dumps(['host_name', 'last_check']),
'filters': json.dumps({
"isnot": {
"host_name": ['localhost'],
"description": ["test_keystone"]
}
})
}
response = self.app.post_json("/v2/status/hosts", params=query)
expected = [{"host_name": "ws-arbiter", "last_check": 1429405764}]
self.assertEqual(json.loads(response.body), expected)

View File

@ -0,0 +1,94 @@
# Copyright 2015 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import httpretty
from surveil.tests.api import functionalTest
class TestStatusServices(functionalTest.FunctionalTest):
def setUp(self):
super(TestStatusServices, self).setUp()
self.influxdb_response = (
'{"results":[{"series":[{"name":"SERVICE_STATE","tags":{"host_nam'
'e":"test_keystone","service_description":"Check KeyStone service'
'."},"columns":["time","last_check","last_state_change","output",'
'"state","state_type"],"values":[["2015-04-19T18:20:34Z",1.429467'
'634e+09,1.429467636632134e+09,"There was no suitable authenticat'
'ion url for this request",3,"SOFT"]]},{"name":"SERVICE_STATE","t'
'ags":{"host_name":"ws-arbiter","service_description":"check-ws-a'
'rbiter"},"columns":["time","last_check","last_state_change","out'
'put","state","state_type"],"values":[["2015-04-19T18:20:33Z",1.4'
'29467633e+09,1.429467635629833e+09,"TCP OK - 0.000 second respon'
'se time on port 7760",0,"HARD"]]}]}]}'
)
@httpretty.activate
def test_get_all_services(self):
httpretty.register_uri(httpretty.GET,
"http://influxdb:8086/query",
body=self.influxdb_response)
response = self.app.get("/v2/status/services")
expected = [
{'description': 'Check KeyStone service.',
'last_state_change': 1429467636,
'plugin_output':
'There was no suitable authentication url for this request',
'last_check': 1429467634,
'state': 3,
'host_name': 'test_keystone',
'service_description': 'Check KeyStone service.'},
{'description': 'check-ws-arbiter',
'last_state_change': 1429467635,
'plugin_output':
'TCP OK - 0.000 second response time on port 7760',
'last_check': 1429467633,
'state': 0,
'host_name': 'ws-arbiter',
'service_description': 'check-ws-arbiter'}
]
self.assertEqual(json.loads(response.body), expected)
@httpretty.activate
def test_query_services(self):
httpretty.register_uri(httpretty.GET,
"http://influxdb:8086/query",
body=self.influxdb_response)
query = {
'fields': json.dumps(['host_name', 'service_description']),
'filters': json.dumps({
"isnot": {
"host_name": ['ws-arbiter'],
},
"is": {
"service_description": ["Check KeyStone service."]
}
})
}
response = self.app.post_json("/v2/status/services", params=query)
expected = [
{'host_name': 'test_keystone',
'service_description': 'Check KeyStone service.'}
]
self.assertEqual(json.loads(response.body), expected)

View File

@ -14,6 +14,7 @@
import os
import influxdb
import mongomock
from oslo_config import cfg
import pecan
@ -37,20 +38,26 @@ class FunctionalTest(base.BaseTestCase):
self.mongoconnection = mongomock.Connection()
self.ws_arbiter_url = "http://localhost:7760"
self.influxdb_client = influxdb.InfluxDBClient.from_DSN(
'influxdb://root:root@influxdb:8086/db'
)
class TestHook(hooks.PecanHook):
def __init__(self, mongoclient, wsarbiterurl):
def __init__(self, mongoclient, wsarbiterurl, influxdb_client):
self.mongoclient = mongoclient
self.ws_arbiter_url = wsarbiterurl
self.influxdb_client = influxdb_client
def before(self, state):
state.request.mongo_connection = self.mongoclient
state.request.ws_arbiter_url = self.ws_arbiter_url
state.request.influxdb_client = self.influxdb_client
app_hooks = [
TestHook(
self.mongoconnection,
self.ws_arbiter_url
self.ws_arbiter_url,
self.influxdb_client
)
]

View File

View File

@ -0,0 +1,86 @@
# Copyright 2015 - Savoir-Faire Linux inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
from surveil.api.datamodel.status import live_query
from surveil.api.handlers.status import liveQuery_filter as query_filter
from surveil.tests import base
class LiveQueryFilterTest(base.BaseTestCase):
def setUp(self):
self.items = [
{"description": "localhost",
"last_state_change": 1429400991,
"plugin_output": "OK - localhost: rta 0.047ms, lost 0%",
"last_check": 1429400990,
"state": 0,
"host_name": "localhost"},
{"description": "test_keystone",
"last_state_change": 1429400986,
"plugin_output": "OK - 127.0.0.1: rta 0.045ms, lost 0%",
"last_check": 1429400984, "state": 2,
"host_name": "test_keystone"},
{"description": "ws-arbiter",
"last_state_change": 1429400991,
"plugin_output": "OK - localhost: rta 0.042ms, lost 0%",
"last_check": 1429400990,
"state": 2,
"host_name": "ws-arbiter"}
]
def test_query_builder_filter_isnot(self):
query = live_query.LiveQuery(
fields=json.dumps(['host_name', 'last_check']),
filters=json.dumps({
"isnot": {
"state": [0, 1],
"description": ["test_keystone"]
}
})
)
result = query_filter.filter_dict_list_with_live_query(
self.items,
query
)
expected = [{"last_check": 1429400990, "host_name": "ws-arbiter"}]
self.assertItemsEqual(result, expected)
def test_query_builder_filter_is(self):
query = live_query.LiveQuery(
fields=json.dumps(['host_name']),
filters=json.dumps({
"is": {
"state": [0],
"description": ["localhost"]
},
"isnot": {
"state": [1]
}
})
)
result = query_filter.filter_dict_list_with_live_query(
self.items,
query
)
expected = [{"host_name": "localhost"}]
self.assertItemsEqual(result, expected)