This repository has been archived by the owner on Feb 2, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from mbarnes/clusters-endpoint
Add clusters endpoint and tests
- Loading branch information
Showing
4 changed files
with
232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
commissaire.handlers.clusters module | ||
==================================== | ||
|
||
.. automodule:: commissaire.handlers.clusters | ||
:members: | ||
:undoc-members: | ||
:show-inheritance: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# Copyright (C) 2016 Red Hat, Inc | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Affero General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Affero General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import falcon | ||
import etcd | ||
import json | ||
|
||
from commissaire.model import Model | ||
from commissaire.resource import Resource | ||
|
||
|
||
class Cluster(Model): | ||
""" | ||
Representation of a Cluster. | ||
""" | ||
_json_type = dict | ||
_attributes = ( | ||
'status', 'hosts') | ||
|
||
|
||
class Clusters(Model): | ||
""" | ||
Representation of a group of one or more Clusters. | ||
""" | ||
_json_type = list | ||
_attributes = ('clusters',) | ||
|
||
|
||
class ClustersResource(Resource): | ||
""" | ||
Resource for working with Clusters. | ||
""" | ||
|
||
def on_get(self, req, resp): | ||
""" | ||
Handles GET requests for Clusters. | ||
:param req: Request instance that will be passed through. | ||
:type req: falcon.Request | ||
:param resp: Response instance that will be passed through. | ||
:type resp: falcon.Response | ||
""" | ||
try: | ||
clusters_dir = self.store.get('/commissaire/clusters/') | ||
except etcd.EtcdKeyNotFound: | ||
self.logger.warn( | ||
'Etcd does not have any clusters. Returning [] and 404.') | ||
resp.status = falcon.HTTP_404 | ||
req.context['model'] = None | ||
return | ||
results = [] | ||
# Don't let an empty clusters directory through | ||
if len(clusters_dir._children): | ||
for cluster in clusters_dir.leaves: | ||
results.append(Cluster(**json.loads(cluster.value))) | ||
resp.status = falcon.HTTP_200 | ||
req.context['model'] = Clusters(clusters=results) | ||
else: | ||
self.logger.debug( | ||
'Etcd has a clusters directory but no content.') | ||
resp.status = falcon.HTTP_200 | ||
req.context['model'] = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# Copyright (C) 2016 Red Hat, Inc | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Affero General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Affero General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
""" | ||
Test cases for the commissaire.handlers.clusters module. | ||
""" | ||
|
||
import json | ||
|
||
import etcd | ||
import falcon | ||
|
||
from . import TestCase | ||
from falcon.testing.helpers import create_environ | ||
from mock import MagicMock | ||
from commissaire.handlers import clusters | ||
from commissaire.script import create_app | ||
from commissaire.middleware import JSONify | ||
|
||
|
||
class Test_Clusters(TestCase): | ||
""" | ||
Tests for the Clusters model. | ||
""" | ||
# XXX: Based on Test_Hosts | ||
|
||
def test_clusters_creation(self): | ||
""" | ||
Verify Clusters model. | ||
""" | ||
# Make sure clusters is required | ||
self.assertRaises( | ||
TypeError, | ||
clusters.Clusters | ||
) | ||
|
||
# Make sure an empty Clusters is still valid | ||
clusters_model = clusters.Clusters(clusters=[]) | ||
self.assertEquals( | ||
'[]', | ||
clusters_model.to_json()) | ||
|
||
# Make sure a Cluster is accepted as expected | ||
clusters_model = clusters.Clusters( | ||
clusters=[clusters.Cluster( | ||
status='ok', | ||
hosts={'total': 1, | ||
'available': 1, | ||
'unavailable': 0})]) | ||
self.assertEquals(1, len(clusters_model.clusters)) | ||
self.assertEquals(type(str()), type(clusters_model.to_json())) | ||
|
||
# Make sure other instances are not accepted | ||
clusters_model = clusters.Clusters(clusters=[object()]) | ||
|
||
|
||
class Test_ClustersResource(TestCase): | ||
""" | ||
Tests for the Clusters resource. | ||
""" | ||
# XXX: Based on Test_HostsResource | ||
|
||
acluster = ('{"status": "ok",' | ||
' "hosts": {"total": 1, "available": 1, "unavailable": 0}}') | ||
|
||
def before(self): | ||
self.api = falcon.API(middleware=[JSONify()]) | ||
self.datasource = etcd.Client() | ||
self.return_value = MagicMock(etcd.EtcdResult) | ||
self.datasource.get = MagicMock(name='get') | ||
self.datasource.get.return_value = self.return_value | ||
self.resource = clusters.ClustersResource(self.datasource) | ||
self.api.add_route('/api/v0/clusters', self.resource) | ||
|
||
def test_clusters_listing(self): | ||
""" | ||
Verify listing clusters. | ||
""" | ||
child = MagicMock(value=self.acluster) | ||
self.return_value._children = [child] | ||
self.return_value.leaves = self.return_value._children | ||
|
||
body = self.simulate_request('/api/v0/clusters') | ||
# datasource's get should have been called once | ||
self.assertEquals(1, self.datasource.get.call_count) | ||
self.assertEqual(self.srmock.status, falcon.HTTP_200) | ||
self.assertEqual( | ||
[json.loads(self.acluster)], | ||
json.loads(body[0])) | ||
|
||
def test_clusters_listing_with_no_hosts(self): | ||
""" | ||
Verify listing clusters. | ||
""" | ||
child = MagicMock(value=self.acluster) | ||
self.return_value._children = [] | ||
self.return_value.leaves = self.return_value._children | ||
|
||
body = self.simulate_request('/api/v0/clusters') | ||
# datasource's get should have been called once | ||
self.assertEquals(1, self.datasource.get.call_count) | ||
self.assertEqual(self.srmock.status, falcon.HTTP_200) | ||
self.assertEqual({}, json.loads(body[0])) | ||
|
||
def test_clusters_listing_with_no_etcd_result(self): | ||
""" | ||
Verify listing clusters handles no etcd result properly. | ||
""" | ||
self.datasource.get.side_effect = etcd.EtcdKeyNotFound | ||
|
||
body = self.simulate_request('/api/v0/clusters') | ||
# datasource's get should have been called once | ||
self.assertEquals(1, self.datasource.get.call_count) | ||
self.assertEqual(self.srmock.status, falcon.HTTP_404) | ||
self.assertEqual('{}', body[0]) |