-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Basic Structure #5
base: develop
Are you sure you want to change the base?
Changes from 24 commits
63590c4
a0a4a1a
7a1ce10
f5733a4
0d3cf5b
76e47a7
33b69b6
4129a5e
6103cd3
0d56ca3
b576615
5c1b300
ef6f987
ca1a0f5
6614c12
95642c8
ed966e8
ee11d02
a578983
e632caa
bd88e15
09b44bd
26297a8
215a1a5
839f52c
1510445
3156873
ba00f2f
8959150
0eff03a
aa26361
a8bdcb8
b2f4425
562efac
cd1e570
6dac2c3
819b715
f317a7c
2e5099c
d7268cb
8faeee7
6efb915
4081893
f5b6a8b
94ddbe9
b6fe20e
d6db3c4
8fcdf5f
d53e546
8b1bcff
d206f34
6a2260c
1e8a311
adb61a3
b1159c2
b25a26c
3e31fb6
e14fcfb
36fc8a3
e72898f
bdb4806
c56e01d
407fc4b
99af59d
883fe7f
92ea031
800e5d9
9dfb7f1
cc1a0f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.pyc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
recursive-include public * |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
================================================================= | ||
Add fixed bugs in this file. Select a format to add bugs. | ||
================================================================= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
======================================================================== | ||
Add already implemented. | ||
======================================================================== |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
================================================================= | ||
Add known bugs in this file. Select a format to add bugs. | ||
================================================================= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
======================================================================== | ||
Add blueprints that needs to implmented. | ||
======================================================================== |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import pecan | ||
|
||
from dockyard.api import config as api_config | ||
from oslo_config import cfg | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think some requirement file also need to be created which specify the dependency modules(ex. oslo_config) for running dockyard. |
||
from pecan import make_app | ||
|
||
from dockyard import model | ||
|
||
|
||
API_SERVICE_OPT = [ | ||
cfg.PortOpt('port', | ||
default=5869, | ||
help='Port for the dockyard service.'), | ||
cfg.IPOpt('host', | ||
default='127.0.0.1', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This address should be 0.0.0.0 so that anyone from remote machine is able to communicate to this server. |
||
help='Listening address for dockyard service'), | ||
] | ||
|
||
CONF = cfg.CONF | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure but there must be a way to define values of these parameters through configuration file. So that these default values can be overridden. 💯 |
||
opt_group = cfg.OptGroup(name='default', | ||
title='Group for the default values for dockyard api') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. values for dockyard ---> values of dockyard |
||
CONF.register_group(opt_group) | ||
CONF.register_opts(API_SERVICE_OPT, opt_group) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Provide a sample file also for the reference, so that it can be used for development purpose. |
||
|
||
def get_pecan_config(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of this function, we have to identify and then remove if not required. |
||
# Set up the pecan configuration | ||
filename = api_config.__file__.replace('.pyc', '.py') | ||
return pecan.configuration.conf_from_file(filename) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think specific import can be done here, from pecan import configuration, need to check any guideline, use better and consistent. |
||
|
||
def setup_app(config=None): | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Write documentation for the each class and method of the class or function. |
||
if not config: | ||
config = get_pecan_config() | ||
|
||
model.init_model() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not being used but it will be useful, when databases will be initialized at the start of the application. |
||
app_conf = dict(config.app) | ||
|
||
return make_app( | ||
app_conf.pop('root'), | ||
logging=getattr(config, 'logging', {}), | ||
**app_conf | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Pecan Application Configurations | ||
app = { | ||
'root': 'dockyard.controllers.root.RootController', | ||
'modules': ['dockyard', 'dockyard.api'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per documentation, for modules key values should be one. You can have two values but recommended is one. Therefor correct it and put only one required value. |
||
'static_root': '%(confdir)s/public', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per documentation, The directory where your static files can be found (relative to the project root). Pecan comes with middleware that can be used to serve static files (like CSS and Javascript files) during development. i think, for out project static files are not required therefor, these it needs to be considered, whether we should keep it or not. |
||
'template_path': '%(confdir)s/dockyard/templates', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per documentation: Discuss and make sure that it should be removed if not required in this project. |
||
'debug': True, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is ok right now but in production environment, it should not be in the debug mode. |
||
'errors': { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check all the options after this is really being used in the project. |
||
404: '/error/404', | ||
'__force_dict__': True | ||
}, | ||
'acl_public_routes': [ | ||
'/', | ||
'/v1', | ||
], | ||
|
||
} | ||
|
||
# Custom Configurations must be in Python dictionary format:: | ||
# | ||
# foo = {'bar':'baz'} | ||
# | ||
# All configurations are accessible at:: | ||
# pecan.conf |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from wsgiref import simple_server | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is ok to use this server but we should atleast know, why this server is being used not any other server. It is better, we do a bit of research on it. It will help us in understanding about servers. |
||
|
||
from oslo_config import cfg | ||
from oslo_log import log as logging | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logging not used in this module There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently application is running in foreground, we need to make it run as a service. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
from dockyard.api import app as api_app | ||
|
||
def main(): | ||
app = api_app.setup_app() | ||
|
||
# create the wsgi server and start it | ||
host, port = cfg.CONF.default.host, cfg.CONF.default.port | ||
srv = simple_server.make_server(host, port, app) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have to decide about loggin polices, As logging is not being done now. |
||
srv.serve_forever() | ||
|
||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
import sys | ||
import io | ||
import json | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. base.py can be removed if not used |
||
from oslo_log import log as logging | ||
|
||
# python 2 and python 3 compatibility library | ||
from six import iteritems | ||
|
||
try: | ||
import urllib3 | ||
except ImportError: | ||
raise ImportError('python client requires urllib3') | ||
|
||
try: | ||
# for python3 | ||
from urllib.parse import urlencode | ||
except ImportError: | ||
# for python2 | ||
from urllib import urlencode | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class RESTResponse(io.IOBase): | ||
|
||
def __init__(self, resp): | ||
self.urllib3_response = resp | ||
self.status = resp.status | ||
self.reason = resp.reason | ||
self.data = resp.data | ||
|
||
def getheaders(self): | ||
""" | ||
Returns a dictionary of the response headers. | ||
""" | ||
return self.urllib3_response.getheaders() | ||
|
||
def getheader(self, name, default=None): | ||
""" | ||
Returns a given response header. | ||
""" | ||
return self.urllib3_response.getheader(name, default) | ||
|
||
|
||
class RESTClientObject(object): | ||
|
||
def __init__(self, pools_size=4): | ||
# http pool manager | ||
self.pool_manager = urllib3.PoolManager( | ||
num_pools=pools_size | ||
) | ||
|
||
def agent(self, url): | ||
""" | ||
Use `urllib3.util.parse_url` for backward compatibility. | ||
Return proper pool manager for the http/https schemes. | ||
""" | ||
url = urllib3.util.parse_url(url) | ||
scheme = url.scheme | ||
if scheme == 'https': | ||
return self.ssl_pool_manager | ||
else: | ||
return self.pool_manager | ||
|
||
def request(self, method, url, query_params=None, headers=None, | ||
body=None, post_params=None): | ||
""" | ||
:param method: http request method | ||
:param url: http request url | ||
:param query_params: query parameters in the url | ||
:param headers: http request headers | ||
:param body: request json body, for `application/json` | ||
:param post_params: request post parameters, | ||
`application/x-www-form-urlencode` | ||
and `multipart/form-data` | ||
""" | ||
method = method.upper() | ||
assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', 'PATCH'] | ||
|
||
if post_params and body: | ||
raise ValueError( | ||
"body parameter cannot be used with post_params parameter." | ||
) | ||
|
||
post_params = post_params or {} | ||
headers = headers or {} | ||
|
||
if 'Content-Type' not in headers: | ||
headers['Content-Type'] = 'application/json' | ||
|
||
# For `POST`, `PUT`, `PATCH` | ||
if method in ['POST', 'PUT', 'PATCH']: | ||
if query_params: | ||
url += '?' + urlencode(query_params) | ||
if headers['Content-Type'] == 'application/json': | ||
response = self.agent(url).request(method, url, | ||
body=json.dumps(body), | ||
headers=headers) | ||
if headers['Content-Type'] == 'application/x-www-form-urlencoded': | ||
response = self.agent(url).request(method, url, | ||
encode_multipart=False, | ||
headers=headers) | ||
if headers['Content-Type'] == 'multipart/form-data': | ||
# must del headers['Content-Type'], or the correct Content-Type | ||
# which generated by urllib3 will be overwritten. | ||
del headers['Content-Type'] | ||
response = self.agent(url).request(method, url, | ||
encode_multipart=True, | ||
headers=headers) | ||
# For `GET`, `HEAD`, `DELETE` | ||
else: | ||
response = self.agent(url).request(method, url, | ||
headers=headers) | ||
response = RESTResponse(response) | ||
|
||
# In the python 3, the response.data is bytes. | ||
# we need to decode it to string. | ||
if sys.version_info > (3,): | ||
response.data = response.data.decode('utf8') | ||
# log response body | ||
#logger.debug("response body: %s" % response.data) | ||
|
||
if response.status not in range(200, 206): | ||
raise ApiException(http_resp=response) | ||
|
||
return response | ||
|
||
def GET(self, url, headers=None, query_params=None): | ||
return self.request("GET", url, | ||
headers=headers, | ||
query_params=query_params) | ||
|
||
def HEAD(self, url, headers=None, query_params=None): | ||
return self.request("HEAD", url, | ||
headers=headers, | ||
query_params=query_params) | ||
|
||
def DELETE(self, url, headers=None, query_params=None): | ||
return self.request("DELETE", url, | ||
headers=headers, | ||
query_params=query_params) | ||
|
||
def POST(self, url, headers=None, query_params=None, post_params=None, body=None): | ||
return self.request("POST", url, | ||
headers=headers, | ||
query_params=query_params, | ||
post_params=post_params, | ||
body=body) | ||
|
||
def PUT(self, url, headers=None, query_params=None, post_params=None, body=None): | ||
return self.request("PUT", url, | ||
headers=headers, | ||
query_params=query_params, | ||
post_params=post_params, | ||
body=body) | ||
|
||
def PATCH(self, url, headers=None, query_params=None, post_params=None, body=None): | ||
return self.request("PATCH", url, | ||
headers=headers, | ||
query_params=query_params, | ||
post_params=post_params, | ||
body=body) | ||
|
||
|
||
class ApiException(Exception): | ||
|
||
def __init__(self, status=None, reason=None, http_resp=None): | ||
if http_resp: | ||
self.status = http_resp.status | ||
self.reason = http_resp.reason | ||
self.body = http_resp.data | ||
self.headers = http_resp.getheaders() | ||
else: | ||
self.status = status | ||
self.reason = reason | ||
self.body = None | ||
self.headers = None | ||
|
||
def __str__(self): | ||
""" | ||
Custom error messages for exception | ||
""" | ||
error_message = "({0})\n"\ | ||
"Reason: {1}\n".format(self.status, self.reason) | ||
if self.headers: | ||
error_message += "HTTP response headers: {0}\n".format(self.headers) | ||
|
||
if self.body: | ||
error_message += "HTTP response body: {0}\n".format(self.body) | ||
|
||
return error_message | ||
|
||
class RESTClient(object): | ||
""" | ||
A class with methods to perform JSON requests. | ||
""" | ||
|
||
def __init__(self): | ||
self.IMPL = RESTClientObject() | ||
|
||
def request(self, *n, **kw): | ||
""" | ||
Perform a REST request and parse the response. | ||
""" | ||
return self.IMPL.request(*n, **kw) | ||
|
||
def GET(self, *n, **kw): | ||
""" | ||
Perform a GET request using `RESTClient.request()`. | ||
""" | ||
return self.IMPL.GET(*n, **kw) | ||
|
||
def HEAD(self, *n, **kw): | ||
""" | ||
Perform a HEAD request using `RESTClient.request()`. | ||
""" | ||
return self.IMPL.GET(*n, **kw) | ||
|
||
def POST(self, *n, **kw): | ||
""" | ||
Perform a POST request using `RESTClient.request()` | ||
""" | ||
return self.IMPL.POST(*n, **kw) | ||
|
||
def PUT(self, *n, **kw): | ||
""" | ||
Perform a PUT request using `RESTClient.request()` | ||
""" | ||
return self.IMPL.PUT(*n, **kw) | ||
|
||
def PATCH(self, *n, **kw): | ||
""" | ||
Perform a PATCH request using `RESTClient.request()` | ||
""" | ||
return self.IMPL.PATCH(*n, **kw) | ||
|
||
def DELETE(self, *n, **kw): | ||
""" | ||
Perform a DELETE request using `RESTClient.request()` | ||
""" | ||
return self.IMPL.DELETE(*n, **kw) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from oslo_config import cfg | ||
|
||
class Cluster(object): | ||
def __init__(self): | ||
pass | ||
|
||
def register(self, cluster_id, host_ip, port): | ||
pass | ||
|
||
def unregister(self, cluster_id, host_ip): | ||
pass | ||
|
||
def get_hosts(self): | ||
return cfg.CONF.membership.hosts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Write a better membership algorithm because this one always adds its own host only. We have to decide about membership protocol to be used in this product. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct importing sequence as per standard given in pep8.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other style checks defined by pep8 should also be added and tested.