Filtering by environment statuses added

Tests improved
Test data generation added
Checking of aggregation requests added

Blueprint: send-anon-usage
Change-Id: I0b76ff368a8d6e5a2bb8d598195257d052151f45
This commit is contained in:
Alexander Kislitsky 2014-11-12 12:43:47 +03:00
parent fc83766fc5
commit c584b27b9d
5 changed files with 362 additions and 288 deletions

View File

@ -15,7 +15,7 @@
from collections import namedtuple
import datetime
from elasticsearch import Elasticsearch
from random import randint
import random
from unittest2.case import TestCase
import uuid
@ -64,6 +64,104 @@ class ElasticTest(TestCase):
migrator.create_indices()
self.es.cluster.health(wait_for_status='yellow', request_timeout=1)
def load_data(self):
pass
def gen_id(self, id_range=(0, 1000000)):
return random.randint(*id_range)
def generate_node(
self,
roles_range=(0, 5),
node_roles=('compute', 'controller', 'cinder', 'ceph-osd',
'zabbix', 'mongo'),
oses=('Ubuntu', 'CentOs', 'Ubuntu LTS XX'),
node_statuses = ('ready', 'discover', 'provisioning',
'provisioned', 'deploying', 'error')
):
roles = []
for _ in xrange(random.randint(*roles_range)):
roles.append(random.choice(node_roles))
node = {
'id': self.gen_id(),
'roles': roles,
'os': random.choice(oses),
'status': random.choice(node_statuses)
}
return node
def generate_cluster(
self,
nodes_range=(0, 100),
oses=('Ubuntu', 'CentOs', 'Ubuntu LTS XX'),
release_names=('Juno on CentOS 6.5', 'Juno on Ubuntu 12.04.4'),
release_versions=('6.0 TechPreview', '6.0 GA', '6.1'),
cluster_statuses=('new', 'deployment', 'stopped', 'operational',
'error', 'remove', 'update', 'update_error'),
libvirt_names=('qemu', 'kvm', 'vCenter')
):
nodes_num = random.randint(*nodes_range)
cluster = {
'id': self.gen_id(),
'nodes_num': nodes_num,
'release': {
'os': random.choice(oses),
'name': random.choice(release_names),
'version': random.choice(release_versions),
},
'status': random.choice(cluster_statuses),
'nodes': [],
'attributes': {
'libvirt_type': random.choice(libvirt_names)
}
}
for _ in xrange(nodes_num):
cluster['nodes'].append(self.generate_node())
return cluster
def generate_structure(
self,
clusters_num_range=(0, 10),
unallocated_nodes_num_range=(0, 20)
):
mn_uid = '{}'.format(uuid.uuid4())
clusters_num = random.randint(*clusters_num_range)
fuel_release = {
'release': "XX",
'api': 1,
'nailgun_sha': "Unknown build",
'astute_sha': "Unknown build",
'fuellib_sha': "Unknown build",
'ostf_sha': "Unknown build",
'feature_groups': ['experimental', 'mirantis']
}
structure = {
'master_node_uid': mn_uid,
'fuel_release': fuel_release,
'clusters_num': clusters_num,
'clusters': [],
'unallocated_nodes_num_range': random.randint(
*unallocated_nodes_num_range),
'allocated_nodes_num': 0
}
for _ in xrange(clusters_num):
cluster = self.generate_cluster()
structure['clusters'].append(cluster)
structure['allocated_nodes_num'] += cluster['nodes_num']
return structure
def generate_data(self, installations_num=100):
structures = []
for _ in xrange(installations_num):
structure = self.generate_structure()
self.es.index(config.INDEX_FUEL, config.DOC_TYPE_STRUCTURE,
body=structure, id=structure['master_node_uid'])
structures.append(structure)
self.es.indices.refresh(config.INDEX_FUEL)
return structures
class MigrationTest(ElasticTest, DbTest):
@ -102,7 +200,7 @@ class MigrationTest(ElasticTest, DbTest):
def create_dumb_action_log(self):
mn_uid = '{}'.format(uuid.uuid4())
external_id = randint(1, 10000)
external_id = random.randint(1, 10000)
db_session.add(ActionLog(master_node_uid=mn_uid,
external_id=external_id))
db_session.commit()

View File

@ -0,0 +1,78 @@
# Copyright 2014 Mirantis, 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 migration import config
from migration.test.base import ElasticTest
class LibvirtTypesDistribution(ElasticTest):
def test_report(self):
installations_num = 100
structures = self.generate_data(installations_num=installations_num)
statuses = ["operational", "error"]
query = {
"size": 0,
"aggs": {
"clusters": {
"nested": {
"path": "clusters"
},
"aggs": {
"statuses": {
"filter": {
"terms": {"status": statuses}
},
"aggs": {
"attributes": {
"nested": {
"path": "clusters.attributes"
},
"aggs": {
"libvirt_types": {
"terms": {
"field": "libvirt_type"
}
}
}
}
}
}
}
}
}
}
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=query)
# checking filtered clusters num
filtered_statuses = resp['aggregations']['clusters']['statuses']
actual_clusters_num = filtered_statuses['doc_count']
expected_clusters_num = 0
total_clusters_num = 0
for structure in structures:
clusters_in_statuses = filter(lambda c: c['status'] in statuses,
structure['clusters'])
expected_clusters_num += len(clusters_in_statuses)
total_clusters_num += structure['clusters_num']
self.assertGreater(total_clusters_num, actual_clusters_num)
self.assertEquals(expected_clusters_num, actual_clusters_num)
# checking number of filtered libvirt types and clusters
libvirt_types = filtered_statuses['attributes']['libvirt_types']
self.assertEquals(
expected_clusters_num,
sum(d['doc_count'] for d in libvirt_types['buckets'])
)

View File

@ -13,148 +13,38 @@
# under the License.
from migration import config
from migration.test.base import AggsCheck
from migration.test.base import ElasticTest
class NodesDistribution(ElasticTest):
def test_report(self):
docs = [
{
'master_node_uid': 'x0',
'allocated_nodes_num': 1,
'unallocated_nodes_num': 4
},
{
'master_node_uid': 'x1',
'allocated_nodes_num': 7,
'unallocated_nodes_num': 0
},
{
'master_node_uid': 'x11',
'allocated_nodes_num': 7,
'unallocated_nodes_num': 0
},
{
'master_node_uid': 'x12',
'allocated_nodes_num': 5,
'unallocated_nodes_num': 0
},
{
'master_node_uid': 'x2',
'allocated_nodes_num': 13,
'unallocated_nodes_num': 10
},
{
'master_node_uid': 'x4',
'allocated_nodes_num': 0,
'unallocated_nodes_num': 0
},
{
'master_node_uid': 'x5',
'allocated_nodes_num': 0,
'unallocated_nodes_num': 2
},
structures = self.generate_data()
statuses = ["operational", "error"]
ranges = [
{"to": 75},
{"from": 75, "to": 85},
{"from": 85}
]
for doc in docs:
self.es.index(config.INDEX_FUEL, config.DOC_TYPE_STRUCTURE,
doc, id=doc['master_node_uid'])
self.es.indices.refresh(config.INDEX_FUEL)
# nodes distribution request
nodes_distribution = {
"size": 0,
"aggs": {
"nodes_distribution": {
"histogram": {
"field": "allocated_nodes_num",
"interval": 1
}
}
}
}
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=nodes_distribution)
result = resp['aggregations']['nodes_distribution']['buckets']
self.assertGreaterEqual(len(docs), len(result))
checks = (
AggsCheck(0, 2),
AggsCheck(1, 1),
AggsCheck(5, 1),
AggsCheck(7, 2),
AggsCheck(13, 1)
)
self.assertEquals(len(checks), len(result))
for idx, check in enumerate(checks):
to_check = result[idx]
self.assertEquals(check, AggsCheck(**to_check))
# range includes 'from', excludes 'to'
nodes_ranges = {
"size": 0,
"aggs": {
"nodes_ranges": {
"range": {
"field": "allocated_nodes_num",
"ranges": [
{"to": 5},
{"from": 5, "to": 10},
{"from": 10}
]
}
}
}
}
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=nodes_ranges)
expected = [
{'key': '*-5.0', 'doc_count': 3},
{'key': '5.0-10.0', 'doc_count': 3},
{'key': '10.0-*', 'doc_count': 1},
]
result = resp['aggregations']['nodes_ranges']['buckets']
for idx, check in enumerate(expected):
res = result[idx]
self.assertEquals(AggsCheck(**check),
AggsCheck(
key=res['key'],
doc_count=res['doc_count']
))
self.assertEquals(3, result[0]['doc_count'])
self.assertEquals('*-5.0', result[0]['key'])
def test_clusters_by_nodes_num(self):
docs = [
{'master_node_uid': 'x0', 'clusters': [{'nodes_num': 1}]},
{'master_node_uid': 'x1', 'clusters': [
{'nodes_num': 1}, {'nodes_num': 2}]},
{'master_node_uid': 'x2', 'clusters': [{'nodes_num': 0}]},
{'master_node_uid': 'x3', 'clusters': [{'nodes_num': 2}]},
{'master_node_uid': 'x4', 'clusters': [{'nodes_num': 1}]}
]
for doc in docs:
self.es.index(config.INDEX_FUEL, config.DOC_TYPE_STRUCTURE, doc,
id=doc['master_node_uid'])
self.es.indices.refresh(config.INDEX_FUEL)
# checking calculation
clusters_by_nodes_num = {
"size": 0,
"aggs": {
"clusters": {
"nested": {"path": "clusters"},
"nested": {
"path": "clusters"
},
"aggs": {
"clusters_by_nodes_num": {
# calculating nodes num
"terms": {
"field": "clusters.nodes_num"
"statuses": {
"filter": {
"terms": {"status": statuses}
},
"aggs": {
"nodes_ranges": {
"range": {
"field": "nodes_num",
"ranges": ranges
}
}
}
}
}
@ -164,13 +54,23 @@ class NodesDistribution(ElasticTest):
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=clusters_by_nodes_num)
clusters = resp['aggregations']['clusters']
result = clusters['clusters_by_nodes_num']['buckets']
expected = [
AggsCheck(1, 3),
AggsCheck(2, 2),
AggsCheck(0, 1)
]
actual = [AggsCheck(**d) for d in result]
self.assertListEqual(sorted(expected), sorted(actual))
body=nodes_distribution)
filtered_statuses = resp['aggregations']['clusters']['statuses']
nodes_ranges = filtered_statuses['nodes_ranges']['buckets']
actual_ranges = [d['doc_count'] for d in nodes_ranges]
expected_envs_num = 0
expected_ranges = [0] * len(ranges)
for structure in structures:
clusters_in_statuses = filter(lambda c: c['status'] in statuses,
structure['clusters'])
expected_envs_num += len(clusters_in_statuses)
for cluster in clusters_in_statuses:
for idx, r in enumerate(ranges):
f = r.get('from', 0)
t = r.get('to')
nodes_num = cluster['nodes_num']
if nodes_num >= f and (t is None or nodes_num < t):
expected_ranges[idx] += 1
continue
self.assertListEqual(expected_ranges, actual_ranges)

View File

@ -12,6 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from collections import defaultdict
import six
from migration import config
from migration.test.base import AggsCheck
from migration.test.base import ElasticTest
@ -19,7 +22,7 @@ from migration.test.base import ElasticTest
class OsDistribution(ElasticTest):
def test_report(self):
def test_os_analyzer(self):
docs = [
{
'master_node_uid': 'x0',
@ -100,3 +103,63 @@ class OsDistribution(ElasticTest):
sorted(checks),
sorted(AggsCheck(**d) for d in result)
)
def test_report(self):
structures = self.generate_data()
statuses = ["operational", "error"]
# nodes oses distribution request
oses_list = {
"size": 0,
"aggs": {
"clusters": {
"nested": {
"path": "clusters"
},
"aggs": {
"statuses": {
"filter": {
"terms": {"status": statuses}
},
"aggs": {
"release": {
"nested": {
"path": "clusters.release"
},
"aggs": {
"oses": {
"terms": {
"field": "os"
}
}
}
}
}
}
}
}
}
}
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=oses_list)
filtered_clusters = resp['aggregations']['clusters']['statuses']
result = filtered_clusters['release']['oses']['buckets']
actual_oses = dict([(d['key'], d['doc_count']) for d in result])
expected_oses = defaultdict(int)
expected_clusters_num = 0
for structure in structures:
clusters_in_statuses = filter(lambda c: c['status'] in statuses,
structure['clusters'])
expected_clusters_num += len(clusters_in_statuses)
for cluster in clusters_in_statuses:
os = str.lower(cluster['release']['os'])
expected_oses[os] += 1
# checking aggregation result
self.assertDictEqual(expected_oses, actual_oses)
# checking clusters are filtered
self.assertEquals(expected_clusters_num,
sum(six.itervalues(actual_oses)))

View File

@ -12,8 +12,7 @@
# 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 random
import uuid
from collections import defaultdict
from migration import config
from migration.test.base import ElasticTest
@ -21,134 +20,8 @@ from migration.test.base import ElasticTest
class Reports(ElasticTest):
def load_data(self):
pass
def gen_id(self, id_range=(0, 1000000)):
return random.randint(*id_range)
def generate_node(
self,
roles_range=(0, 5),
node_roles=('compute', 'controller', 'cinder', 'ceph-osd',
'zabbix', 'mongo'),
oses=('Ubuntu', 'CentOs', 'Ubuntu LTS XX'),
node_statuses = ('ready', 'discover', 'provisioning',
'provisioned', 'deploying', 'error')
):
roles = []
for _ in xrange(random.randint(*roles_range)):
roles.append(random.choice(node_roles))
node = {
'id': self.gen_id(),
'roles': roles,
'os': random.choice(oses),
'status': random.choice(node_statuses)
}
return node
def generate_cluster(
self,
nodes_range=(0, 100),
oses=('Ubuntu', 'CentOs', 'Ubuntu LTS XX'),
release_names=('Juno on CentOS 6.5', 'Juno on Ubuntu 12.04.4'),
release_versions=('6.0 TechPreview', '6.0 GA', '6.1'),
cluster_statuses=('new', 'deployment', 'stopped', 'operational',
'error', 'remove', 'update', 'update_error'),
libvirt_names=('qemu', 'kvm', 'vCenter')
):
nodes_num = random.randint(*nodes_range)
cluster = {
'id': self.gen_id(),
'nodes_num': nodes_num,
'release': {
'os': random.choice(oses),
'name': random.choice(release_names),
'version': random.choice(release_versions),
},
'status': random.choice(cluster_statuses),
'nodes': [],
'attributes': {
'libvirt_type': random.choice(libvirt_names)
}
}
for _ in xrange(nodes_num):
cluster['nodes'].append(self.generate_node())
return cluster
def generate_structure(
self,
clusters_num_range=(0, 10),
unallocated_nodes_num_range=(0, 20)
):
mn_uid = '{}'.format(uuid.uuid4())
clusters_num = random.randint(*clusters_num_range)
fuel_release = {
'release': "XX",
'api': 1,
'nailgun_sha': "Unknown build",
'astute_sha': "Unknown build",
'fuellib_sha': "Unknown build",
'ostf_sha': "Unknown build",
'feature_groups': ['experimental', 'mirantis']
}
structure = {
'master_node_uid': mn_uid,
'fuel_release': fuel_release,
'clusters_num': clusters_num,
'clusters': [],
'unallocated_nodes_num_range': random.randint(
*unallocated_nodes_num_range),
'allocated_nodes_num': 0
}
for _ in xrange(clusters_num):
cluster = self.generate_cluster()
structure['clusters'].append(cluster)
structure['allocated_nodes_num'] += cluster['nodes_num']
return structure
def generate_data(self, installations_num=100):
for _ in xrange(installations_num):
structure = self.generate_structure()
self.es.index(config.INDEX_FUEL, config.DOC_TYPE_STRUCTURE,
body=structure, id=structure['master_node_uid'])
self.es.indices.refresh(config.INDEX_FUEL)
def test_oses_distribution(self):
self.generate_data(installations_num=100)
# nodes oses distribution request
oses_list = {
"size": 0,
"aggs": {
"clusters": {
"nested": {
"path": "clusters"
},
"aggs": {
"release": {
"nested": {
"path": "clusters.release"
},
"aggs": {
"oses": {
"terms": {
"field": "os"
}
}
}
}
}
}
}
}
self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=oses_list)
def test_nodes_distribution(self):
self.generate_data(installations_num=100)
structures = self.generate_data(installations_num=100)
nodes_distribution = {
"size": 0,
"aggs": {
@ -160,14 +33,51 @@ class Reports(ElasticTest):
}
}
}
self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=nodes_distribution)
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=nodes_distribution)
distrs = resp['aggregations']['nodes_distribution']['buckets']
actual_distr = dict([(d['key'], d['doc_count']) for d in distrs])
expected_distr = defaultdict(int)
for structure in structures:
expected_distr[structure['allocated_nodes_num']] += 1
self.assertDictEqual(expected_distr, actual_distr)
def test_libvirt_type_distribution(self):
self.generate_data(installations_num=100)
# nodes oses distribution request
libvirt_types_req = {
def test_envs_distribution(self):
structures = self.generate_data(installations_num=100)
envs_distribution = {
"size": 0,
"aggs": {
"envs_distribution": {
"histogram": {
"field": "clusters_num",
"interval": 1
}
}
}
}
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=envs_distribution)
distrs = resp['aggregations']['envs_distribution']['buckets']
actual_distr = dict([(d['key'], d['doc_count']) for d in distrs])
expected_distr = defaultdict(int)
for structure in structures:
expected_distr[structure['clusters_num']] += 1
self.assertDictEqual(expected_distr, actual_distr)
def test_installations_number(self):
installations_num = 150
self.generate_data(installations_num=installations_num)
resp = self.es.count(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE)
self.assertEquals(installations_num, resp['count'])
def test_filtration(self):
installations_num = 100
structures = self.generate_data(installations_num=installations_num)
statuses = ["operational", "error"]
query = {
"size": 0,
"aggs": {
"clusters": {
@ -175,14 +85,21 @@ class Reports(ElasticTest):
"path": "clusters"
},
"aggs": {
"attributes": {
"nested": {
"path": "clusters.attributes"
"statuses": {
"filter": {
"terms": {"status": statuses}
},
"aggs": {
"libvirt_types": {
"terms": {
"field": "libvirt_type"
"attributes": {
"nested": {
"path": "clusters.attributes"
},
"aggs": {
"libvirt_types": {
"terms": {
"field": "libvirt_type"
}
}
}
}
}
@ -191,6 +108,24 @@ class Reports(ElasticTest):
}
}
}
self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=libvirt_types_req)
resp = self.es.search(index=config.INDEX_FUEL,
doc_type=config.DOC_TYPE_STRUCTURE,
body=query)
# checking filtered clusters num
filtered_statuses = resp['aggregations']['clusters']['statuses']
actual_clusters_num = filtered_statuses['doc_count']
expected_clusters_num = 0
for structure in structures:
expected_clusters_num += len(
filter(lambda c: c['status'] in statuses,
structure['clusters'])
)
self.assertEquals(expected_clusters_num, actual_clusters_num)
# checking number of filtered libvirt types and clusters
libvirt_types = filtered_statuses['attributes']['libvirt_types']
self.assertEquals(
expected_clusters_num,
sum(d['doc_count'] for d in libvirt_types['buckets'])
)