Skip to content

Commit

Permalink
Merge pull request #2 from seecloud/skeleton
Browse files Browse the repository at this point in the history
Initial skeleton
  • Loading branch information
boris-42 committed Dec 6, 2016
2 parents 3c5d53d + 490e54e commit fae1257
Show file tree
Hide file tree
Showing 21 changed files with 481 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[run]
branch = True
source = kbackend

[report]
ignore_errors = True
precision = 3

[html]
directory = .test_result/cover
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tests_result/
.tox/
.coverage
.coverage.*
Expand Down
22 changes: 22 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
language: python

install:
- pip install tox

env:
- TOXENV=pep8
- TOXENV=py27
- TOXENV=py33
- TOXENV=py34

script:
- tox -e ${TOXENV}

matrix:
include:
- python: "2.7"
install:
- pip install tox
- pip install coveralls
env: TOXENV=cover
after_success: coveralls
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM ubuntu:16.04

RUN apt-get update && apt-get install --yes wget python-dev build-essential

# ubuntu's pip is too old to work with the version of requests we
# require, so get pip with get-pip.py
RUN wget https://bootstrap.pypa.io/get-pip.py && \
python get-pip.py && \
rm -f get-pip.py

COPY . /app
WORKDIR /app

RUN python setup.py install
RUN pip install -r requirements.txt

EXPOSE 5000
CMD ["./entrypoint-api.sh"]
5 changes: 5 additions & 0 deletions entrypoint-api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

gunicorn -w 4 -b 0.0.0.0:5000 notify.main:app &

wait -n
24 changes: 24 additions & 0 deletions etc/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"flask": {
"PORT": 5000,
"HOST": "0.0.0.0",
"DEBUG": false
},
"backend": {
"type": "elastic",
"connection": [{"host": "127.0.0.1", "port": 9200}]
},
"notify_backends": {
"sf": {
"salesforce": {
"atuh_url": "https://somedomain.my.salesforce.com",
"username": "babalbalba",
"password": "abablabal",
"environment": "what?",
"client_id": "...",
"client_secret": "...",
"organization_id": "...."
}
}
}
}
Empty file added notify/__init__.py
Empty file.
Empty file added notify/api/__init__.py
Empty file.
Empty file added notify/api/v1/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions notify/api/v1/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2016: Mirantis Inc.
# All Rights Reserved.
#
# 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 logging

import flask

from notify import config


LOG = logging.getLogger("api")
LOG.setLevel(config.get_config().get("logging", {}).get("level", "INFO"))


bp = flask.Blueprint("alert", __name__)


@bp.route("/alert", methods=["POST"])
def send_alert(period):
return flask.jsonify({})


def get_blueprints():
return [["", bp]]
113 changes: 113 additions & 0 deletions notify/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Copyright 2016: Mirantis Inc.
# All Rights Reserved.
#
# 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 logging
import os

import jsonschema


CONF = None

DEFAULT_CONF = {
"flask": {
"HOST": "0.0.0.0",
"PORT": 5000,
"DEBUG": False
},
"backend": {
"type": "elastic",
"connection": [{"host": "127.0.0.1", "port": 9200}]
},
"notify_backends": {}
}

CONF_SCHEMA = {
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"properties": {
"flask": {
"type": "object",
"properties": {
"PORT": {"type": "integer"},
"HOST": {"type": "string"},
"DEBUG": {"type": "boolean"}
}
},
"backend": {
"type": "object",
"properties": {
"type": {"type": "string"},
"connection": {
"type": "array",
"items": {
"type": "object",
"properties": {
"host": {"type": "string"},
"port": {"type": "integer"}
},
"required": ["host"]
},
"minItems": 1
}
},
"required": ["type", "connection"]
},
"notify_backends": {
"type": "object",
"properties": {
"*": {
"type": "object",
"properties": {
"salesforce": {
"type": "object",
"properties": {
"atuh_url": {"type": "string"},
"username": {"type": "string"},
"password": {"type": "string"},
"environment": {"type": "string"},
"client_id": {"type": "string"},
"client_secret": {"type": "string"},
"organization_id": {"type": "string"}
}
}
}
}
}
}
},
"required": ["flask", "backend", "notify_backends"]
}


def get_config():
"""Get cached configuration.
:returns: application config
:rtype: dict
"""
global CONF
if not CONF:
path = os.environ.get("NOTIFY_CONF", "/etc/notify/config.json")
try:
cfg = json.load(open(path))
logging.info("Config is '%s'" % path)
jsonschema.validate(cfg, CONF_SCHEMA)
CONF = cfg
except (IOError, jsonschema.exceptions.ValidationError) as e:
logging.warning("Failed to load config from '%s': %s" % (path, e))
CONF = DEFAULT_CONF
return CONF
45 changes: 45 additions & 0 deletions notify/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2016: Mirantis Inc.
# All Rights Reserved.
#
# 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 flask
from flask_helpers import routing

from notify.api.v1 import api
from notify import config


app = flask.Flask(__name__, static_folder=None)
app.config.update(config.get_config()["flask"])


@app.errorhandler(404)
def not_found(error):
return flask.jsonify({"error": "Not Found"}), 404


for url_prefix, blueprint in api.get_blueprints():
app.register_blueprint(blueprint, url_prefix="/api/v1%s" % url_prefix)


app = routing.add_routing_map(app, html_uri=None, json_uri="/")


def main():
app.run(host=app.config.get("HOST", "0.0.0.0"),
port=app.config.get("PORT", 5000))


if __name__ == "__main__":
main()
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
gunicorn==19.6.0
Flask==0.11.1
flask-helpers==0.1
requests==2.11.1
jsonschema==2.5.1
future==0.16.0
schedule==0.4.2
elasticsearch==5.0.1
16 changes: 16 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python

from setuptools import setup

setup(name="notify",
version="0.1",
description="Notify service",
url="https://github.com/seecloud/notify",
author="<name>",
author_email="<name>@mirantis.com",
packages=["notify"],
entry_points={
"console_scripts": [
"notify-api = notify.main:main"
],
})
11 changes: 11 additions & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
hacking>=0.9.2,<0.10
pytest>=2.7,<=2.9.2
pytest-cov>=2.2.1,<=2.3.0
pytest-html==1.10.1

coverage>=3.6
ddt>=1.0.1
mock>=2.0

testtools>=1.4.0
future==0.16.0
Empty file added tests/__init__.py
Empty file.
Empty file added tests/unit/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions tests/unit/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2016: Mirantis Inc.
# All Rights Reserved.
#
# 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 testtools

from notify import main


class TestCase(testtools.TestCase):

def setUp(self):
super(TestCase, self).setUp()
self.app = main.app.test_client()

def get(self, *args, **kwargs):
rv = self.app.get(*args, **kwargs)
return rv.status_code, json.loads(rv.data.decode())
Loading

0 comments on commit fae1257

Please sign in to comment.