PEP-8 and PEP-257: ''' to """

This commit is contained in:
Wari Wahab 2013-10-25 16:28:22 +08:00
parent d2094f8b60
commit c192809517
11 changed files with 134 additions and 134 deletions

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# pylint: disable=C0103,W0622
'''
"""
Sphinx documentation for salt-api
'''
"""
import os
import sys
@ -10,14 +10,14 @@ from sphinx.directives import TocTree
# pylint: disable=R0903
class Mock(object):
'''
"""
Mock out specified imports
This allows autodoc to do it's thing without having oodles of req'd
installed libs. This doesn't work with ``import *`` imports.
http://read-the-docs.readthedocs.org/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules
'''
"""
def __init__(self, *args, **kwargs):
pass

View File

@ -1,6 +1,6 @@
'''
"""
Make api awesomeness
'''
"""
# Import Python libs
import inspect
@ -13,19 +13,19 @@ import salt.utils
from salt.exceptions import SaltException, EauthAuthenticationError
class APIClient(object):
'''
"""
Provide a uniform method of accessing the various client interfaces in Salt
in the form of low-data data structures. For example:
>>> client = APIClient(__opts__)
>>> lowstate = {'client': 'local', 'tgt': '*', 'fun': 'test.ping', 'arg': ''}
>>> client.run(lowstate)
'''
"""
def __init__(self, opts):
self.opts = opts
def run(self, low):
'''
"""
Execute the specified function in the specified client by passing the
lowstate
@ -35,7 +35,7 @@ class APIClient(object):
If 'wheel' or 'runner' prefixes fun then use associated salt client given
by prefix in the specified 'sync' or 'async' mode.
Otherwise use local salt client in the given 'sync' or 'async' mode
'''
"""
if not 'client' in low:
low['client'] = 'async'
@ -63,24 +63,24 @@ class APIClient(object):
return ret
def local_async(self, *args, **kwargs):
'''
"""
Wrap LocalClient for running :ref:`execution modules <all-salt.modules>`
and immediately return the job ID. The results of the job can then be
retrieved at a later time.
.. seealso:: :ref:`python-api`
'''
"""
local = salt.client.LocalClient(self.opts['conf_file'])
return local.run_job(*args, **kwargs)
async = local_async # default async client
def local_sync(self, *args, **kwargs):
'''
"""
Wrap LocalClient for running :ref:`execution modules <all-salt.modules>`
.. seealso:: :ref:`python-api`
'''
"""
local = salt.client.LocalClient(self.opts['conf_file'])
return local.cmd(*args, **kwargs)
@ -88,9 +88,9 @@ class APIClient(object):
sync = local_sync # default sync client
def runner_sync(self, fun, **kwargs):
'''
"""
Wrap RunnerClient for executing :ref:`runner modules <all-salt.runners>`
'''
"""
runner = salt.runner.RunnerClient(self.opts)
return runner.low(fun, kwargs)
@ -98,9 +98,9 @@ class APIClient(object):
runner_async = runner_sync # until we get an runner_async
def wheel_sync(self, fun, **kwargs):
'''
"""
Wrap Wheel to enable executing :ref:`wheel modules <all-salt.wheel>`
'''
"""
kwargs['fun'] = fun
wheel = salt.wheel.Wheel(self.opts)
return wheel.master_call(**kwargs)

View File

@ -1,6 +1,6 @@
'''
"""
CLI entry-point for salt-api
'''
"""
# Import python libs
import sys
import logging
@ -26,9 +26,9 @@ log = logging.getLogger(__name__)
class SaltAPI(OptionParser, ConfigDirMixIn, LogLevelMixIn, PidfileMixin,
DaemonMixIn, MergeConfigMixIn):
'''
"""
The cli parser object used to fire up the salt api system.
'''
"""
__metaclass__ = OptionParserMeta
VERSION = saltapi.version.__version__
@ -42,9 +42,9 @@ class SaltAPI(OptionParser, ConfigDirMixIn, LogLevelMixIn, PidfileMixin,
return saltapi.config.api_config(self.get_config_file_path())
def run(self):
'''
"""
Run the api
'''
"""
self.parse_args()
try:
if self.config['verify_env']:

View File

@ -1,6 +1,6 @@
'''
"""
The main entry point for salt-api
'''
"""
# Import python libs
import logging
import multiprocessing
@ -11,15 +11,15 @@ import saltapi.loader
logger = logging.getLogger(__name__)
class SaltAPIClient(object):
'''
'''
"""
"""
def __init__(self, opts):
self.opts = opts
def run(self):
'''
"""
Load and start all available api modules
'''
"""
netapi = saltapi.loader.netapi(self.opts)
for fun in netapi:
if fun.endswith('.start'):

View File

@ -1,6 +1,6 @@
'''
"""
Manage configuration files in salt-api
'''
"""
# Import salt libs
import salt.config
@ -14,10 +14,10 @@ DEFAULT_API_OPTS = {
def api_config(path):
'''
"""
Read in the salt master config file and add additional configs that
need to be stubbed out for salt-api
'''
"""
# Let's grab a copy of salt's master default opts
defaults = salt.config.DEFAULT_MASTER_OPTS
# Let's override them with salt-api's required defaults

View File

@ -1,6 +1,6 @@
'''
"""
The salt api module loader interface
'''
"""
# Import python libs
import os
@ -10,9 +10,9 @@ import saltapi
def netapi(opts):
'''
"""
Return the network api functions
'''
"""
load = salt.loader._create_loader(
opts,
'netapi',
@ -22,10 +22,10 @@ def netapi(opts):
return load.gen_functions()
def runner(opts):
'''
"""
Load the runners, this function bypasses the issue with the altered
basepath
'''
"""
load = salt.loader._create_loader(
opts,
'runners',

View File

@ -1,8 +1,8 @@
'''
"""
A script to start the CherryPy WSGI server
This is run by ``salt-api`` and started in a multiprocess.
'''
"""
# pylint: disable=C0103
# Import Python libs
@ -58,9 +58,9 @@ def __virtual__():
return False
def verify_certs(self, *args):
'''
"""
Sanity checking for the specified SSL certificates
'''
"""
msg = ("Could not find a certificate: {0}\n"
"If you want to quickly generate a self-signed certificate, "
"use the tls.create_self_signed_cert function in Salt")
@ -70,9 +70,9 @@ def verify_certs(self, *args):
raise Exception(msg.format(arg))
def start():
'''
"""
Start the server loop
'''
"""
from . import app
root, apiopts, conf = app.get_app(__opts__)

View File

@ -1,4 +1,4 @@
'''
"""
A REST API for Salt
===================
@ -153,7 +153,7 @@ functionality is available at that URL. The other URLs are largely convenience
URLs that wrap that main entry point with shorthand or specialized
functionality.
'''
"""
# We need a custom pylintrc here...
# pylint: disable=W0212,E1101,C0103,R0201,W0221,W0613
@ -179,10 +179,10 @@ logger = logging.getLogger(__name__)
def salt_token_tool():
'''
"""
If the custom authentication header is supplied, put it in the cookie dict
so the rest of the session-based auth works as intended
'''
"""
x_auth = cherrypy.request.headers.get('X-Auth-Token', None)
# X-Auth-Token header trumps session cookie
@ -191,10 +191,10 @@ def salt_token_tool():
def salt_ip_verify_tool():
'''
"""
If there is a list of restricted IPs, verify current
client is coming from one of those IPs.
'''
"""
# This is overly cumbersome and crude,
# But, it's also safe... ish...
salt_config = cherrypy.config.get('saltopts', None)
@ -218,9 +218,9 @@ def salt_ip_verify_tool():
def salt_auth_tool():
'''
"""
Redirect all unauthenticated requests to the login page
'''
"""
# Redirect to the login page if the session hasn't been authed
if not cherrypy.session.has_key('token'):
raise cherrypy.InternalRedirect('/login')
@ -239,14 +239,14 @@ ct_out_map = (
)
def hypermedia_handler(*args, **kwargs):
'''
"""
Determine the best output format based on the Accept header, execute the
regular handler, and transform the output to the request content type (even
if it's an error).
:param args: Pass args through to the main handler
:param kwargs: Pass kwargs through to the main handler
'''
"""
# Execute the real handler. Handle or pass-through any errors we know how
# to handle (auth & HTTP errors). Reformat any errors we don't know how to
# handle as a data structure.
@ -282,12 +282,12 @@ def hypermedia_handler(*args, **kwargs):
def hypermedia_out():
'''
"""
Determine the best handler for the requested content type
Wrap the normal handler and transform the output from that handler into the
requested content type
'''
"""
request = cherrypy.serving.request
request._hypermedia_inner_handler = request.handler
request.handler = hypermedia_handler
@ -297,9 +297,9 @@ def hypermedia_out():
@functools.wraps
def process_request_body(fn):
'''
"""
A decorator to skip a processor function if process_request_body is False
'''
"""
def wrapped(*args, **kwargs):
if cherrypy.request.process_request_body != False:
fn(*args, **kwargs)
@ -307,7 +307,7 @@ def process_request_body(fn):
def urlencoded_processor(entity):
'''
"""
Accept x-www-form-urlencoded data (run through CherryPy's formatter)
and reformat it into a Low State data structure.
@ -321,7 +321,7 @@ def urlencoded_processor(entity):
-d fun='test.kwarg' -d arg='one=1' -d arg='two=2'
:param entity: raw POST data
'''
"""
# First call out to CherryPy's default processor
cherrypy._cpreqbody.process_urlencoded(entity)
lowdata = entity.params
@ -336,11 +336,11 @@ def urlencoded_processor(entity):
@process_request_body
def json_processor(entity):
'''
"""
Unserialize raw POST data in JSON format to a Python data structure.
:param entity: raw POST data
'''
"""
body = entity.fp.read()
try:
cherrypy.serving.request.lowstate = json.loads(body)
@ -350,11 +350,11 @@ def json_processor(entity):
@process_request_body
def yaml_processor(entity):
'''
"""
Unserialize raw POST data in YAML format to a Python data structure.
:param entity: raw POST data
'''
"""
body = entity.fp.read()
try:
cherrypy.serving.request.lowstate = yaml.load(body)
@ -363,7 +363,7 @@ def yaml_processor(entity):
def hypermedia_in():
'''
"""
Unserialize POST/PUT data of a specified Content-Type.
The following custom processors all are intended to format Low State data
@ -371,7 +371,7 @@ def hypermedia_in():
:raises HTTPError: if the request contains a Content-Type that we do not
have a processor for
'''
"""
# Be liberal in what you accept
ct_in_map = {
'application/x-www-form-urlencoded': urlencoded_processor,
@ -393,11 +393,11 @@ def hypermedia_in():
class LowDataAdapter(object):
'''
"""
The primary entry point to the REST API. All functionality is available
through this URL. The other available URLs provide convenience wrappers
around this URL.
'''
"""
exposed = True
_cp_config = {
@ -419,11 +419,11 @@ class LowDataAdapter(object):
self.api = saltapi.APIClient(self.opts)
def exec_lowstate(self):
'''
"""
Pull a Low State data structure from request and execute the low-data
chunks through Salt. The low-data chunks will be updated to include the
authorization token for the current session.
'''
"""
lowstate = cherrypy.request.lowstate
token = cherrypy.session.get('token', None)
@ -433,7 +433,7 @@ class LowDataAdapter(object):
yield self.api.run(chunk)
def GET(self):
'''
"""
.. http:get:: /
An explanation of the API with links of where to go next.
@ -458,7 +458,7 @@ class LowDataAdapter(object):
:status 200: success
:status 401: authentication required
:status 406: requested Content-Type not available
'''
"""
import inspect
# Grab all available client interfaces
@ -476,7 +476,7 @@ class LowDataAdapter(object):
}
def POST(self, **kwargs):
'''
"""
The primary execution interface for the rest of the API
.. http:post:: /
@ -527,7 +527,7 @@ class LowDataAdapter(object):
:status 200: success
:status 401: authentication required
:status 406: requested Content-Type not available
'''
"""
return {
'return': list(self.exec_lowstate()),
}
@ -535,7 +535,7 @@ class LowDataAdapter(object):
class Minions(LowDataAdapter):
def GET(self, mid=None):
'''
"""
A convenience URL for getting lists of minions or getting minion
details
@ -571,7 +571,7 @@ class Minions(LowDataAdapter):
:status 200: success
:status 401: authentication required
:status 406: requested Content-Type not available
'''
"""
cherrypy.request.lowstate = [{
'client': 'local', 'tgt': mid or '*', 'fun': 'grains.items',
}]
@ -580,7 +580,7 @@ class Minions(LowDataAdapter):
}
def POST(self, **kwargs):
'''
"""
Start an execution command and immediately return the job id
.. http:post:: /minions
@ -634,7 +634,7 @@ class Minions(LowDataAdapter):
:status 202: success
:status 401: authentication required
:status 406: requested :mailheader:`Content-Type` not available
'''
"""
for chunk in cherrypy.request.lowstate:
chunk['client'] = 'local_async'
job_data = list(self.exec_lowstate())
@ -651,7 +651,7 @@ class Minions(LowDataAdapter):
class Jobs(LowDataAdapter):
def GET(self, jid=None):
'''
"""
A convenience URL for getting lists of previously run jobs or getting
the return from a single job
@ -717,7 +717,7 @@ class Jobs(LowDataAdapter):
:status 200: success
:status 401: authentication required
:status 406: requested Content-Type not available
'''
"""
cherrypy.request.lowstate = [{
'client': 'runner',
'fun': 'jobs.lookup_jid' if jid else 'jobs.list_jobs',
@ -729,7 +729,7 @@ class Jobs(LowDataAdapter):
class Login(LowDataAdapter):
'''
"""
All interactions with this REST API must be authenticated. Authentication
is performed through Salt's eauth system. You must set the eauth backend
and allowed users by editing the :conf_master:`external_auth` section in
@ -743,7 +743,7 @@ class Login(LowDataAdapter):
If the request is initiated programmatically, the request must contain a
:mailheader:`X-Auth-Token` header with valid and active session id.
'''
"""
_cp_config = dict(LowDataAdapter._cp_config, **{
'tools.salt_token.on': False,
'tools.salt_auth.on': False,
@ -756,7 +756,7 @@ class Login(LowDataAdapter):
self.auth = salt.auth.LoadAuth(self.opts)
def GET(self):
'''
"""
Present the login interface
.. http:get:: /login
@ -782,7 +782,7 @@ class Login(LowDataAdapter):
:status 401: authentication required
:status 406: requested Content-Type not available
'''
"""
cherrypy.response.status = '401 Unauthorized'
cherrypy.response.headers['WWW-Authenticate'] = 'Session'
@ -792,7 +792,7 @@ class Login(LowDataAdapter):
}
def POST(self, **kwargs):
'''
"""
Authenticate against Salt's eauth system
.. versionchanged:: 0.8.0
@ -851,7 +851,7 @@ class Login(LowDataAdapter):
:status 200: success
:status 401: could not authenticate using provided credentials
:status 406: requested Content-Type not available
'''
"""
# the urlencoded_processor will wrap this in a list
if isinstance(cherrypy.serving.request.lowstate, list):
creds = cherrypy.serving.request.lowstate[0]
@ -890,11 +890,11 @@ class Logout(LowDataAdapter):
})
def POST(self):
'''
"""
Destroy the currently active session and expire the session cookie
.. versionadded:: 0.8.0
'''
"""
cherrypy.lib.sessions.expire() # set client-side to expire
cherrypy.session.regenerate() # replace server-side with new
@ -909,16 +909,16 @@ class Run(LowDataAdapter):
})
def exec_lowstate(self):
'''
"""
Override exec_lowstate to avoid pulling token from the session
'''
"""
lowstate = cherrypy.request.lowstate
for chunk in lowstate:
yield self.api.run(chunk)
def POST(self, **kwargs):
'''
"""
Run commands bypassing the normal session handling
.. versionadded:: 0.8.0
@ -971,19 +971,19 @@ class Run(LowDataAdapter):
:status 200: success
:status 401: authentication failed
:status 406: requested Content-Type not available
'''
"""
return {
'return': list(self.exec_lowstate()),
}
class Events(object):
'''
"""
The event bus on the Salt master exposes a large variety of things, notably
when executions are started on the master and also when minions ultimately
return their results. This URL provides a real-time window into a running
Salt infrastructure.
'''
"""
exposed = True
_cp_config = dict(LowDataAdapter._cp_config, **{
@ -1002,7 +1002,7 @@ class Events(object):
self.auth = salt.auth.LoadAuth(self.opts)
def GET(self, token=None):
'''
"""
Return an HTTP stream of the Salt master event bus; this stream is
formatted per the Server Sent Events (SSE) spec
@ -1044,7 +1044,7 @@ class Events(object):
:status 200: success
:status 401: could not authenticate using provided credentials
'''
"""
# Pulling the session token from an URL param is a workaround for
# browsers not supporting CORS in the EventSource API.
if token:
@ -1084,9 +1084,9 @@ class App(object):
class API(object):
'''
"""
Collect configuration and URL map for building the CherryPy app
'''
"""
url_map = {
'index': LowDataAdapter,
'login': Login,
@ -1108,10 +1108,10 @@ class API(object):
setattr(self, self.apiopts.get('app_path', 'app').lstrip('/'), App())
def get_conf(self):
'''
"""
Combine the CherryPy configuration with the rest_cherrypy config values
pulled from the master config and return the CherryPy configuration
'''
"""
conf = {
'global': {
'server.socket_host': self.apiopts.get('host', '0.0.0.0'),
@ -1143,9 +1143,9 @@ class API(object):
def get_app(opts):
'''
"""
Returns a WSGI app and a configuration dictionary
'''
"""
apiopts = opts.get(__name__.rsplit('.', 2)[-2], {}) # rest_cherrypy opts
# Add Salt and salt-api config options to the main CherryPy config dict

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python
'''
"""
Deployment
==========
@ -36,7 +36,7 @@ An example Apache virtual host configuration::
WSGIScriptAlias / /path/to/saltapi/netapi/rest_cherrypy/wsgi.py
</VirtualHost>
'''
"""
# pylint: disable=C0103
import os
@ -44,9 +44,9 @@ import os
import cherrypy
def bootstrap_app():
'''
"""
Grab the opts dict of the master config by trying to import Salt
'''
"""
from . import app
import salt.config
@ -56,11 +56,11 @@ def bootstrap_app():
def get_application(*args):
'''
"""
Returns a WSGI application function. If you supply the WSGI app and config
it will use that, otherwise it will try to obtain them from a local Salt
installation
'''
"""
opts_tuple = args
def wsgi_app(environ, start_response):

View File

@ -1,4 +1,4 @@
'''
"""
A minimalist REST API for Salt
==============================
@ -128,7 +128,7 @@ Usage examples
:status 200: success
:status 401: authentication required
'''
"""
import errno
import json
import os
@ -158,18 +158,18 @@ def __virtual__():
return False
class HTTPError(Exception):
'''
"""
A custom exception that can take action based on an HTTP error code
'''
"""
def __init__(self, code, message):
self.code = code
Exception.__init__(self, '{0}: {1}'.format(code, message))
def mkdir_p(path):
'''
"""
mkdir -p
http://stackoverflow.com/a/600612/127816
'''
"""
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
@ -178,18 +178,18 @@ def mkdir_p(path):
else: raise
def read_body(environ):
'''
"""
Pull the body from the request and return it
'''
"""
length = environ.get('CONTENT_LENGTH', '0')
length = 0 if length == '' else int(length)
return environ['wsgi.input'].read(length)
def get_json(environ):
'''
"""
Return the request body as JSON
'''
"""
content_type = environ.get('CONTENT_TYPE', '')
if content_type != 'application/json':
raise HTTPError(406, 'JSON required')
@ -200,10 +200,10 @@ def get_json(environ):
raise HTTPError(400, exc)
def get_headers(data, extra_headers=None):
'''
"""
Takes the response data as well as any additional headers and returns a
tuple of tuples of headers suitable for passing to start_response()
'''
"""
response_headers = {
'Content-Length': str(len(data)),
}
@ -214,20 +214,20 @@ def get_headers(data, extra_headers=None):
return response_headers.items()
def run_chunk(environ, lowstate):
'''
"""
Expects a list of lowstate dictionaries that are executed and returned in
order
'''
"""
client = environ['SALT_APIClient']
for chunk in lowstate:
yield client.run(chunk)
def dispatch(environ):
'''
"""
Do any path/method dispatching here and return a JSON-serializable data
structure appropriate for the response
'''
"""
method = environ['REQUEST_METHOD'].upper()
if method == 'GET':
@ -240,9 +240,9 @@ def dispatch(environ):
raise HTTPError(405, 'Method Not Allowed')
def saltenviron(environ):
'''
"""
Make Salt's opts dict and the APIClient available in the WSGI environ
'''
"""
if not '__opts__' in locals():
import salt.config
__opts__ = salt.config.client_config(
@ -252,10 +252,10 @@ def saltenviron(environ):
environ['SALT_APIClient'] = saltapi.APIClient(__opts__)
def application(environ, start_response):
'''
"""
Process the request and return a JSON response. Catch errors and return the
appropriate HTTP code.
'''
"""
# Instantiate APIClient once for the whole app
saltenviron(environ)
@ -287,9 +287,9 @@ def application(environ, start_response):
return (ret,)
def start():
'''
"""
Start simple_server()
'''
"""
from wsgiref.simple_server import make_server
short_name = __name__.rsplit('.')[-1]

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
'''
"""
The setup script for saltapi
'''
"""
import os
# Use setuptools only if the user opts-in by setting the USE_SETUPTOOLS env var