Skip to content

Commit e4e1ee3

Browse files
committed
Use oss_lib.onfig for configuration
1 parent 63a7b70 commit e4e1ee3

File tree

15 files changed

+227
-209
lines changed

15 files changed

+227
-209
lines changed

availability/api/v1/api.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@
1717

1818
import flask
1919

20-
from availability import config
2120
from availability import storage
2221

23-
24-
LOG = logging.getLogger("api")
22+
LOG = logging.getLogger(__name__)
2523

2624

2725
def get_period_interval(period):

availability/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# under the License.
1515

1616
import flask
17-
from flask_helpers import routing
17+
from oss_lib import routing
1818

1919
from availability.api.v1 import api
2020
from availability.api.v1 import regions

availability/config.py

Lines changed: 47 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -13,94 +13,68 @@
1313
# License for the specific language governing permissions and limitations
1414
# under the License.
1515

16-
import json
17-
import logging
18-
import os
16+
DEFAULT_CONF_PATH = "/etc/availability/config.json"
1917

20-
import jsonschema
21-
22-
23-
CONF = None
24-
25-
DEFAULT_CONF = {
18+
DEFAULT = {
2619
"backend": {
2720
"type": "elastic",
28-
"connection": [{"host": "127.0.0.1", "port": 9200}]
21+
"connection": [
22+
{"host": "127.0.0.1", "port": 9200},
23+
],
2924
},
30-
"regions": []
25+
"regions": [],
26+
"period": 60,
27+
"connection_timeout": 1,
28+
"read_timeout": 10,
3129
}
3230

33-
CONF_SCHEMA = {
34-
"type": "object",
35-
"$schema": "http://json-schema.org/draft-04/schema",
36-
"properties": {
37-
"backend": {
31+
SCHEMA = {
32+
"backend": {
33+
"type": "object",
34+
"properties": {
35+
"type": {"type": "string"},
36+
"connection": {
37+
"type": "array",
38+
"items": {
39+
# TODO(akscram): Here should be enum.
40+
"type": "object",
41+
"properties": {
42+
"host": {"type": "string"},
43+
"port": {"type": "integer"},
44+
},
45+
"required": ["host"],
46+
"additionalProperties": False,
47+
},
48+
"minItems": 1,
49+
},
50+
},
51+
"required": ["type", "connection"],
52+
"additionalProperties": False,
53+
},
54+
"regions": {
55+
"type": "array",
56+
"items": {
3857
"type": "object",
3958
"properties": {
40-
"type": {"type": "string"},
41-
"connection": {
59+
"name": {"type": "string"},
60+
"services": {
4261
"type": "array",
4362
"items": {
4463
"type": "object",
4564
"properties": {
46-
"host": {"type": "string"},
47-
"port": {"type": "integer"}
65+
"name": {"type": "string"},
66+
"url": {"type": "string"}
4867
},
49-
"required": ["host"]
68+
"required": ["name", "url"],
69+
"additionalProperties": False,
5070
},
51-
"minItems": 1
52-
}
71+
"minItems": 1,
72+
},
5373
},
54-
"required": ["type", "connection"]
55-
},
56-
"regions": {
57-
"type": "array",
58-
"items": {
59-
"type": "object",
60-
"properties": {
61-
"name": {"type": "string"},
62-
"services": {
63-
"type": "array",
64-
"items": {
65-
"type": "object",
66-
"properties": {
67-
"name": {"type": "string"},
68-
"url": {"type": "string"}
69-
},
70-
"required": ["name", "url"]
71-
},
72-
"minItems": 1
73-
}
74-
}
75-
}
74+
"additionalProperties": False,
7675
},
77-
"period": {"type": "number", "minimum": 5},
78-
"connection_timeout": {"type": "number"},
79-
"read_timeout": {"type": "number"},
8076
},
81-
"required": ["backend", "regions"]
77+
"period": {"type": "number", "minimum": 5},
78+
"connection_timeout": {"type": "number"},
79+
"read_timeout": {"type": "number"},
8280
}
83-
84-
85-
def get_config():
86-
"""Get cached configuration.
87-
88-
:returns: application config
89-
:rtype: dict
90-
"""
91-
global CONF
92-
if not CONF:
93-
path = os.environ.get("AVAILABILITY_CONF",
94-
"/etc/availability/config.json")
95-
try:
96-
config = json.load(open(path))
97-
logging.info("Config is '%s'" % path)
98-
jsonschema.validate(config, CONF_SCHEMA)
99-
CONF = config
100-
except IOError as exc:
101-
logging.warning("Failed to load config from '%s': %s", path, exc)
102-
CONF = DEFAULT_CONF
103-
except jsonschema.exceptions.ValidationError as exc:
104-
logging.error("Configuration file %s is not valid: %s", path, exc)
105-
raise
106-
return CONF

availability/main.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515

1616
import argparse
1717

18+
from oss_lib import config
19+
1820
from availability import app
19-
from availability import config
21+
from availability import config as cfg
2022

2123

2224
def main():
23-
config.get_config()
2425
parser = argparse.ArgumentParser()
2526
parser.add_argument("--host",
2627
default="0.0.0.0",
@@ -31,5 +32,10 @@ def main():
3132
default=5000,
3233
help="A port to bind development server. "
3334
"(default 5000)")
34-
args = parser.parse_args()
35+
args = config.process_args("AVAILABILITY",
36+
parser=parser,
37+
default_config_path=cfg.DEFAULT_CONF_PATH,
38+
defaults=cfg.DEFAULT,
39+
validation_schema=cfg.SCHEMA)
40+
app.app.config.update(config.CONF, **{"DEBUG": args.debug})
3541
app.app.run(host=args.host, port=args.port)

availability/storage.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
import logging
1818

1919
import elasticsearch
20+
from oss_lib import config
2021

21-
from availability import config
22+
CONF = config.CONF
23+
LOG = logging.getLogger(__name__)
2224

23-
LOG = logging.getLogger("storage")
2425
NUMBER_OF_SHARDS = 2
2526

2627

@@ -31,7 +32,7 @@ def get_elasticsearch(check_availability=False):
3132
:returns: Elasticsearch or None on failure
3233
:rtype: elasticsearch.Elasticsearch
3334
"""
34-
nodes = config.get_config()["backend"]["connection"]
35+
nodes = CONF["backend"]["connection"]
3536
try:
3637
es = elasticsearch.Elasticsearch(nodes)
3738
if check_availability:

availability/watcher.py

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,15 @@
2222
import uuid
2323

2424
from elasticsearch import exceptions as es_exceptions
25+
from oss_lib import config
2526
import queue
2627
import requests
2728
import schedule
2829

29-
from availability import config
3030
from availability import storage
3131

32-
33-
SERVICE_CONN_TIMEOUT = config.get_config().get("connection_timeout", 1)
34-
SERVICE_READ_TIMEOUT = config.get_config().get("read_timeout", 10)
35-
36-
LOG = logging.getLogger("watcher")
32+
CONF = config.CONF
33+
LOG = logging.getLogger(__name__)
3734

3835

3936
def check_availability(data, results_queue):
@@ -44,8 +41,9 @@ def check_availability(data, results_queue):
4441
:rtype: None
4542
"""
4643
try:
47-
requests.get(data["url"], verify=False, timeout=(SERVICE_CONN_TIMEOUT,
48-
SERVICE_READ_TIMEOUT))
44+
requests.get(data["url"], verify=False,
45+
timeout=(CONF["connection_timeout"],
46+
CONF["read_timeout"]))
4947

5048
data["status"] = 1
5149
except Exception as e:
@@ -104,7 +102,7 @@ def save_availability(results_queue):
104102

105103
def watch_services():
106104
"""Query services of all regions and save results."""
107-
for region in config.get_config().get("regions"):
105+
for region in CONF["regions"]:
108106
for service in region.get("services"):
109107
LOG.info("Checking service '%(name)s' availability on %(url)s"
110108
% service)
@@ -130,18 +128,18 @@ def main(period=None):
130128
This runs infinite availability check with given period.
131129
:param period: period in seconds
132130
"""
133-
if not config.get_config().get("regions"):
131+
if not CONF["regions"]:
134132
LOG.error("No regions configured. Quitting.")
135133
return 1
136134

137-
period = period or config.get_config().get("period", 60)
135+
period = period or CONF["period"]
138136

139-
if SERVICE_CONN_TIMEOUT + SERVICE_READ_TIMEOUT > period:
137+
if CONF["connection_timeout"] + CONF["read_timeout"] > period:
140138
LOG.error("Period can not be lesser than timeout, "
141139
"otherwise threads could crowd round.")
142140
return 1
143141

144-
backend = config.get_config().get("backend")
142+
backend = CONF["backend"]
145143
if backend["type"] != "elastic":
146144
LOG.error("Unexpected backend: %(type)s" % backend)
147145
return 1
@@ -156,10 +154,3 @@ def main(period=None):
156154
while True:
157155
time.sleep(1)
158156
schedule.run_pending()
159-
160-
161-
if __name__ == "__main__":
162-
try:
163-
sys.exit(main())
164-
except KeyboardInterrupt:
165-
LOG.error("Got SIGINT. Quitting...")

availability/wsgi.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@
1313
# License for the specific language governing permissions and limitations
1414
# under the License.
1515

16+
from oss_lib import config
1617

1718
from availability import app
18-
from availability import config
19+
from availability import config as cfg
1920

20-
config.get_config()
21+
22+
config.process_env("AVAILABILITY",
23+
default_config_path=cfg.DEFAULT_CONF_PATH,
24+
defaults=cfg.DEFAULT,
25+
validation_schema=cfg.SCHEMA)
2126

2227
application = app.app

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
gunicorn==19.6.0
22
Flask==0.11.1
3-
flask-helpers==0.1
3+
oss-lib==0.1.1
44
requests==2.11.1
55
jsonschema==2.5.1
66
future==0.16.0

tests/ci/api/populate_elastic.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515

1616
import datetime as dt
1717
import json
18-
import os
1918
import random
2019
import sys
2120
import uuid
2221

22+
from oss_lib import config
23+
24+
from availability import config as cfg
2325
from availability import storage
2426

2527

@@ -57,8 +59,10 @@ def random_status(success_probability=0.7):
5759

5860
def populate_elastic(**kwargs):
5961
started_at = dt.datetime.now()
60-
conf = json.load(open(os.environ.get("AVAILABILITY_CONF")))
61-
regions = {r["name"]: r["services"] for r in conf["regions"]}
62+
config.process_env("AVAILABILITY",
63+
defaults=cfg.DEFAULT,
64+
validation_schema=cfg.SCHEMA)
65+
regions = {r["name"]: r["services"] for r in config.CONF["regions"]}
6266
elastic = storage.get_elasticsearch(check_availability=True)
6367

6468
# Create indices

tests/unit/api/v1/test_api.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import mock
1717

18+
from availability.api.v1 import api
1819
from tests.unit import test
1920

2021

@@ -74,3 +75,37 @@ def test_get_region_availability(self, mock_process_results,
7475
mock_storage.es_search.reset_mock()
7576
mock_process_results.assert_called_once_with("foo_buckets")
7677
mock_process_results.reset_mock()
78+
79+
80+
# TODO(akscram): Just to pass coverage, re-write this test completely.
81+
class ResultsTestCase(test.TestCase):
82+
def test_process_results(self):
83+
buckets = [{
84+
"key": "key_av",
85+
"availability": {"value": 1},
86+
"data": {
87+
"buckets": [
88+
{
89+
"availability": {"value": 1},
90+
"key_as_string": "key_1",
91+
},
92+
{
93+
"availability": {"value": 1},
94+
"key_as_string": "key_2",
95+
},
96+
],
97+
},
98+
}]
99+
expected = {
100+
"availability": {
101+
"key_av": {
102+
"availability": 1,
103+
"availability_data": [
104+
["key_1", 1],
105+
["key_2", 1],
106+
],
107+
},
108+
},
109+
}
110+
result = api.process_results(buckets)
111+
self.assertEqual(result, expected)

0 commit comments

Comments
 (0)