%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/self/root/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/
Upload File :
Create Path :
Current File : //proc/self/root/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyc

�
���^c@@s�dZddlmZmZmZddlZddlZddlZddlmZddl	m
Z
ddlZddlZ
ddlZ
ddlZ
ddlZ
ddlZ
ddlmZddljjZddlZddlZddlZddlZddlZddlZddlZddlmZddl Zddl!Zddl"Zddl#m$Z$m%Z%m&Z&ej'j(j)�ej'j*j+�Z*ej,e-�Z.d	�Z/d
Z0dZ1de2fd
��YZ3defd��YZ4de5fd��YZ6de
j7j8fd��YZ9de9fd��YZ:de9fd��YZ;de;fd��YZ<de;fd��YZ=de;fd��YZ>de;fd��YZ?d e;fd!��YZ@d"�ZAdS(#u�
A non-blocking REST API for Salt
================================

.. py:currentmodule:: salt.netapi.rest_tornado.saltnado

:depends:   - tornado Python module

:configuration: All authentication is done through Salt's :ref:`external auth
    <acl-eauth>` system which requires additional configuration not described
    here.


In order to run rest_tornado with the salt-master
add the following to the Salt master config file.

.. code-block:: yaml

    rest_tornado:
        # can be any port
        port: 8000
        # address to bind to (defaults to 0.0.0.0)
        address: 0.0.0.0
        # socket backlog
        backlog: 128
        ssl_crt: /etc/pki/api/certs/server.crt
        # no need to specify ssl_key if cert and key
        # are in one single file
        ssl_key: /etc/pki/api/certs/server.key
        debug: False
        disable_ssl: False
        webhook_disable_auth: False
        cors_origin: null

.. _rest_tornado-auth:

Authentication
--------------

Authentication is performed by passing a session token with each request.
Tokens are generated via the :py:class:`SaltAuthHandler` URL.

The token may be sent in one of two ways:

* Include a custom header named :mailheader:`X-Auth-Token`.
* Sent via a cookie. This option is a convenience for HTTP clients that
  automatically handle cookie support (such as browsers).

.. seealso:: You can bypass the session handling via the :py:class:`RunSaltAPIHandler` URL.

CORS
----

rest_tornado supports Cross-site HTTP requests out of the box. It is by default
deactivated and controlled by the `cors_origin` config key.

You can allow all origins by settings `cors_origin` to `*`.

You can allow only one origin with this configuration:

.. code-block:: yaml

    rest_tornado:
        cors_origin: http://salt.yourcompany.com

You can also be more specific and select only a few allowed origins by using
a list. For example:

.. code-block:: yaml

    rest_tornado:
        cors_origin:
            - http://salt.yourcompany.com
            - http://salt-preprod.yourcampany.com

The format for origin are full URL, with both scheme and port if not standard.

In this case, rest_tornado will check if the Origin header is in the allowed
list if it's the case allow the origin. Else it will returns nothing,
effectively preventing the origin to make request.

For reference, CORS is a mechanism used by browser to allow (or disallow)
requests made from browser from a different origin than salt-api. It's
complementary to Authentication and mandatory only if you plan to use
a salt client developed as a Javascript browser application.

Usage
-----

Commands are sent to a running Salt master via this module by sending HTTP
requests to the URLs detailed below.

.. admonition:: Content negotiation

    This REST interface is flexible in what data formats it will accept as well
    as what formats it will return (e.g., JSON, YAML, x-www-form-urlencoded).

    * Specify the format of data in the request body by including the
      :mailheader:`Content-Type` header.
    * Specify the desired data format for the response body with the
      :mailheader:`Accept` header.

Data sent in :http:method:`post` and :http:method:`put` requests  must be in
the format of a list of lowstate dictionaries. This allows multiple commands to
be executed in a single HTTP request.

.. glossary::

    lowstate
        A dictionary containing various keys that instruct Salt which command
        to run, where that command lives, any parameters for that command, any
        authentication credentials, what returner to use, etc.

        Salt uses the lowstate data format internally in many places to pass
        command data between functions. Salt also uses lowstate for the
        :ref:`LocalClient() <python-api>` Python API interface.

The following example (in JSON format) causes Salt to execute two commands::

    [{
        "client": "local",
        "tgt": "*",
        "fun": "test.fib",
        "arg": ["10"]
    },
    {
        "client": "runner",
        "fun": "jobs.lookup_jid",
        "jid": "20130603122505459265"
    }]

Multiple commands in a Salt API request will be executed in serial and makes
no gaurantees that all commands will run. Meaning that if test.fib (from the
example above) had an exception, the API would still execute "jobs.lookup_jid".

Responses to these lowstates are an in-order list of dicts containing the
return data, a yaml response could look like::

    - ms-1: true
      ms-2: true
    - ms-1: foo
      ms-2: bar

In the event of an exception while executing a command the return for that lowstate
will be a string, for example if no minions matched the first lowstate we would get
a return like::

    - No minions matched the target. No command was sent, no jid was assigned.
    - ms-1: true
      ms-2: true

.. admonition:: x-www-form-urlencoded

    Sending JSON or YAML in the request body is simple and most flexible,
    however sending data in urlencoded format is also supported with the
    caveats below. It is the default format for HTML forms, many JavaScript
    libraries, and the :command:`curl` command.

    For example, the equivalent to running ``salt '*' test.ping`` is sending
    ``fun=test.ping&arg&client=local&tgt=*`` in the HTTP request body.

    Caveats:

    * Only a single command may be sent per HTTP request.
    * Repeating the ``arg`` parameter multiple times will cause those
      parameters to be combined into a single list.

      Note, some popular frameworks and languages (notably jQuery, PHP, and
      Ruby on Rails) will automatically append empty brackets onto repeated
      parameters. E.g., ``arg=one``, ``arg=two`` will be sent as ``arg[]=one``,
      ``arg[]=two``. This is not supported; send JSON or YAML instead.


.. |req_token| replace:: a session token from :py:class:`~SaltAuthHandler`.
.. |req_accept| replace:: the desired response format.
.. |req_ct| replace:: the format of the request body.

.. |res_ct| replace:: the format of the response body; depends on the
    :mailheader:`Accept` request header.

.. |200| replace:: success
.. |400| replace:: bad request
.. |401| replace:: authentication required
.. |406| replace:: requested Content-Type not available
.. |500| replace:: internal server error
i(tabsolute_importtprint_functiontunicode_literalsN(tcopy(tdefaultdict(tFuture(ttagify(tAuthenticationErrortAuthorizationErrortEauthAuthenticationErrorcK@stjjj|dt|�S(u�
    Invoke salt.utils.json.dumps using the alternate json module loaded using
    salt.utils.json.import_json(). This ensures that we properly encode any
    strings in the object before we perform the serialization.
    t_json_module(tsalttutilstjsontdumps(tobjtkwargs((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_json_dumps�suX-Auth-Tokenu
session_idtTimeoutExceptioncB@seZRS((t__name__t
__module__(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�stAnycB@s eZdZd�Zd�ZRS(uF
    Future that wraps other futures to "block" until one is done
    cC@s8tt|�j�x|D]}|j|j�qWdS(N(tsuperRt__init__tadd_done_callbackt
done_callback(tselftfuturestfuture((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRs
cC@s |j�s|j|�ndS(N(tdonet
set_result(RR((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR
s(RRt__doc__RR(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRs	t
EventListenercB@sheZdZd�Zd�Zed��Zed��Zdejd	d	d�Z
d�Zd�ZRS(
u�
    Class responsible for listening to the salt master event bus and updating
    futures. This is the core of what makes this asynchronous, this allows us to do
    non-blocking work in the main processes and "wait" for an event to happen
    c
C@s�||_||_tjjjd|d|dd|dtdtjj	j
��|_tt�|_
tt�|_i|_|jj|j�dS(Numasterusock_diru	transporttoptstlistentio_loop(tmod_optsR!RRteventt	get_eventtTruettornadotiolooptIOLooptcurrentRtlistttag_maptrequest_mapttimeout_maptset_event_handlert_handle_event_socket_recv(RR$R!((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRs		
	cC@s�||jkrdSxm|j|D]^\}}}|j|||�||jkr!tjjj�j|j|�|j|=q!q!W|j|=dS(ue
        Remove all futures that were waiting for request `request` since it is done waiting
        N(R.t_timeout_futureR/R(R)R*R+tremove_timeout(RtrequestttagtmatcherR((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytclean_by_request.s cC@s4|dks|dkr'td��n|j|�S(Numtag or tag can not be None(tNonet	TypeErrort
startswith(tmtagR5((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytprefix_matcher>scC@s1|dks|dkr'td��n||kS(Numtag or tag can not be None(R8R9(R;R5((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt
exact_matcherDsuc	@s�|jr&t�}|jt��|St�}�dk	rZ�fd�}|j|�n|j||fj|�|j|j|||f�|r�t	j
jj�j
||j|||�}||j|<n|S(u^
        Get an event (asynchronous of course) return a future that will get it later
        c@s tjjj�j�|�dS(N(R(R)R*R+tadd_callback(R(tcallback(sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt
handle_future]sN(t	_finishedRt
set_exceptionRR8RR-tappendR.R(R)R*R+t
call_laterR2R/(	RR4R5R6R?ttimeoutRR@ttimeout_future((R?sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR&Js			*cC@s�||f|jkrdS|j�sR|jt��|j||fj|�nt|j||f�dkr�|j||f=ndS(u+
        Timeout a specific future
        Ni(R-RRBRtremovetlen(RR5R6R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR2jsc	C@s.|jj||jj�\}}xtj|j�D]�\\}}}y|||�}Wn*tk
r�tjddt	�t
}nX|s�q4nx�|D]�}|j�r�q�n|ji|d6|d6�|j||fj
|�||jkr�tjjj�j|j|�|j|=q�q�Wq4WdS(u=
        Callback for events on the event sub socket
        uFailed to run a matcher.texc_infoudatautagN(R%tunpacktserialtsixt	iteritemsR-t	ExceptiontlogterrorR'tFalseRRRGR/R(R)R*R+R3(	RtrawR;tdataR5R6Rt
is_matchedR((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR1vs"!%


 N(
RRRRR7tstaticmethodR<R=t__func__R8R&R2R1(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR s			tBaseSaltAPIHandlercB@s�eZdefdejjjffZd�Zd�Z	e
d��Zd�Zd�Z
d�Zd�Zd	�Zd
�Zd�Zd�Zd
�Zd�Zd�ZRS(uapplication/jsonuapplication/x-yamlcC@sPd|ks$|jd�|jkrL|jd�|jd�|j�tStS(u?
        Verify that the client is in fact one we have
        uclienti�u4400 Invalid Client: Client not found in salt clients(tgettsaltclientst
set_statustwritetfinishRQR'(Rtlow((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_verify_client�s$


cC@s�t|jd�sCtjd�t|jj|jj�|j_nt|d�s�tj	j
d|jj�}i|jd6|jd6tjj
d|jj�jd6dd	6|_nt|d
�s�tjjj|jj�|_ndS(uC
        Initialize the handler before requests are called
        uevent_listeneruinit a listenerusaltclientstmoptsulocalulocal_asyncR!urunnerurunner_asyncu	ckminionsN(thasattrtapplicationROtdebugR R$R!tevent_listenerRtclienttget_local_clientt
run_job_asynctrunnertRunnerClientt	cmd_asyncR8RYRtminionst	CkMinionst	ckminions(Rtlocal_client((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt
initialize�s
	

cC@s1t|jjkr |jjtS|jt�SdS(u0
        The token used for the request
        N(tAUTH_TOKEN_HEADERR4theaderst
get_cookietAUTH_COOKIE_NAME(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyttoken�scC@s%|jo$t|jjj|j��S(u7
        Boolean whether the request is auth'd
        (RstboolRatauthtget_tok(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_verify_auth�sc@s��jjjdd�}g|jd�D]}tj|�d^q(}�fd�}||�\}}|s~�jd�n|�_|�_t	j	��_
t�_�j
��_dS(u�
        Run before get/posts etc. Pre-flight checks:
            - verify that we can speak back to them (compatible accept header)
        uAcceptu*/*u,ic@sKxD|D]<}x3�jD](\}}tj||�r||fSqWqWdS(N(NN(t
ct_out_maptfnmatchR8(tparsed_accept_headertmedia_rangetcontent_typetdumper(R(sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytfind_acceptable_content_type�s

i�N(R4RpRXtsplittcgitparse_headert
send_errorR|R}ttimetstartR't	connectedt
_get_lowstatetlowstate(Rt
accept_headerthRzR~R|R}((RsE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytprepare�s/			cC@s|jjj|�dS(u#
        timeout a session
        N(RaRcR7(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyttimeout_futures�scC@s|j�|`dS(u:
        When the job has been done, lets cleanup
        N(R�RY(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt	on_finish�s
cC@s|j�dS(u;
        If the client disconnects, lets close out
        N(R\(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyton_connection_close�scC@s |jd|j�|j|�S(uB
        Serlialize the output based on the Accept header
        uContent-Type(t
set_headerR|R}(RRS((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt	serializescC@s]i}xP|jjD]B}|j|�}t|�dkrK|d||<q|||<qW|S(u�
        function to get the data from the urlencoded forms
        ignore the data passed in and just get the args from wherever they are
        ii(R4t	argumentst
get_argumentsRH(Rt_RStkeytval((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_form_loader
scC@s�i|jd6tjjjd6tjjjd6tjjjd6tjjjd6}y=tj|j	j
d�\}}||tjj
|��SWn;tk
r�|jd�ntk
r�|jd�nXd	S(
uL
        Deserialize the data based on request content type headers
        u!application/x-www-form-urlencodeduapplication/jsonuapplication/x-yamlu	text/yamlu
text/plainuContent-Typei�i�N(R�RRR
tloadstyamlt	safe_loadR�R�R4RpR(tescapet
native_strtKeyErrorR�t
ValueError(RRSt	ct_in_maptvaluet
parameters((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytdeserializes


cC@s�|jjsdS|j|jj�}t|�|_|rnd|krnt|dt�rn|dg|d<nt|t�s�|g}n|}|S(uA
        Format the incoming data into a lowstate object
        Nuarg(R4tbodyR�Rtrequest_payloadt
isinstanceR,(RRSR�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�.s&cC@sc|jj}|jd�r_|jjjd�}t||d�}|r_|jd|�q_ndS(u*
        Set default CORS headers
        ucors_originuOriginuAccess-Control-Allow-OriginN(RaR$RXR4Rpt_check_cors_originR�(RR$torigintallowed_origin((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytset_default_headersAscO@sx|jjjd�}|jd�}|jddj|��|jdd�|jdd�|jd�|j�d	S(
u<
        Return CORS headers for preflight requests
        uAccess-Control-Request-Headersu,uAccess-Control-Allow-HeadersuAccess-Control-Expose-HeadersuX-Auth-TokenuAccess-Control-Allow-MethodsuOPTIONS, GET, POSTi�N(R4RpRXRR�tjoinRZR\(RtargsRtrequest_headerstallowed_headers((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytoptionsOs
(RRRRRR�t	safe_dumpRxR^RntpropertyRsRwR�R�R�R�R�R�R�R�R�R�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRW�s 					 									tSaltAuthHandlercB@s eZdZd�Zd�ZRS(u$
    Handler for login requests
    cC@sK|jd�|jdd�idd6dd6}|j|j|��dS(	u�
        All logins are done over post, this is a parked endpoint

        .. http:get:: /login

            :status 401: |401|
            :status 406: |406|

        **Example request:**

        .. code-block:: bash

            curl -i localhost:8000/login

        .. code-block:: text

            GET /login HTTP/1.1
            Host: localhost:8000
            Accept: application/json

        **Example response:**

        .. code-block:: text

            HTTP/1.1 401 Unauthorized
            Content-Type: application/json
            Content-Length: 58

            {"status": "401 Unauthorized", "return": "Please log in"}
        i�uWWW-AuthenticateuSessionu401 Unauthorizedustatusu
Please log inureturnN(RZR�R[R�(Rtret((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRXjs



c
C@s|yWt|jt�s&|jd�dSi|jdd6|jdd6|jdd6}Wntk
rx|jd�dSX|jjj|�}d|kr�|jd�dSy�|jjd|d}|j	|d	g�}|j
|j	d
g��d|kr�|dr�t|d�}tg|j�D]$}|j
d�r+|jd�^q+�}x/||@D] }|j
|d
j|��qcWnttt|���}Wnntk
r�|jd�dSttfk
rtjd|j	d�|j	d	�dt�|jd�dSXii|dd6|dd6|dd6|d	d6|dd6|d6gd6}	|j|j|	��dS(u
        :ref:`Authenticate <rest_tornado-auth>` against Salt's eauth system

        .. http:post:: /login

            :reqheader X-Auth-Token: |req_token|
            :reqheader Accept: |req_accept|
            :reqheader Content-Type: |req_ct|

            :form eauth: the eauth backend configured for the user
            :form username: username
            :form password: password

            :status 200: |200|
            :status 400: |400|
            :status 401: |401|
            :status 406: |406|
            :status 500: |500|

        **Example request:**

        .. code-block:: bash

            curl -si localhost:8000/login \
                    -H "Accept: application/json" \
                    -d username='saltuser' \
                    -d password='saltpass' \
                    -d eauth='pam'

        .. code-block:: text

            POST / HTTP/1.1
            Host: localhost:8000
            Content-Length: 42
            Content-Type: application/x-www-form-urlencoded
            Accept: application/json

            username=saltuser&password=saltpass&eauth=pam

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Type: application/json
            Content-Length: 206
            X-Auth-Token: 6d1b722e
            Set-Cookie: session_id=6d1b722e; expires=Sat, 17 Nov 2012 03:23:52 GMT; Path=/

            {"return": {
                "token": "6d1b722e",
                "start": 1363805943.776223,
                "expire": 1363849143.776224,
                "user": "saltuser",
                "eauth": "pam",
                "perms": [
                    "grains.*",
                    "status.*",
                    "sys.*",
                    "test.*"
                ]
            }}
        i�Nuusernameupasswordueauthutokeni�u
external_authunameu*ugroupsu%u{0}%uHConfiguration for external_auth malformed for eauth '%s', and user '%s'.RIi�uexpireustartuuserupermsureturn(R�R�tdictR�R�RaRutmk_tokenR!RXtextendtsettkeystendswithtrstriptformattsortedR,tAttributeErrort
IndexErrorRORbR'R[R�(
RtcredsRsteauthtpermstuser_groupstiteauth_groupstgroupR�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytpost�sT@



=!


(RRRRXR�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�fs	(tSaltAPIHandlercB@s�eZdZd�Zejjd��Zejj	d��Z
ejj	d��Zejj	d��Zejj	d��Z
ejj	d��Zejj	d��Zd	�ZRS(
u'
    Main API handler for base "/"
    cC@s=it|jj��d6dd6}|j|j|��dS(u�
        An endpoint to determine salt-api capabilities

        .. http:get:: /

            :reqheader Accept: |req_accept|

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

        **Example request:**

        .. code-block:: bash

            curl -i localhost:8000

        .. code-block:: text

            GET / HTTP/1.1
            Host: localhost:8000
            Accept: application/json

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Type: application/json
            Content-Legnth: 83

            {"clients": ["local", "local_async", "runner", "runner_async"], "return": "Welcome"}
        uclientsuWelcomeureturnN(R,RYR�R[R�(RR�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRXs"
cC@s+|j�s|jd�dS|j�dS(u
        Send one or more Salt commands (lowstates) in the request body

        .. http:post:: /

            :reqheader X-Auth-Token: |req_token|
            :reqheader Accept: |req_accept|
            :reqheader Content-Type: |req_ct|

            :resheader Content-Type: |res_ct|

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

            :term:`lowstate` data describing Salt commands must be sent in the
            request body.

        **Example request:**

        .. code-block:: bash

            curl -si https://localhost:8000 \
                    -H "Accept: application/x-yaml" \
                    -H "X-Auth-Token: d40d1e1e" \
                    -d client=local \
                    -d tgt='*' \
                    -d fun='test.ping' \
                    -d arg

        .. code-block:: text

            POST / HTTP/1.1
            Host: localhost:8000
            Accept: application/x-yaml
            X-Auth-Token: d40d1e1e
            Content-Length: 36
            Content-Type: application/x-www-form-urlencoded

            fun=test.ping&arg&client=local&tgt=*

        **Example response:**

        Responses are an in-order list of the lowstate's return data. In the
        event of an exception running a command the return will be a string
        instead of a mapping.

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Length: 200
            Allow: GET, HEAD, POST
            Content-Type: application/x-yaml

            return:
            - ms-0: true
                ms-1: true
                ms-2: true
                ms-3: true
                ms-4: true

        .. admonition:: multiple commands

            Note that if multiple :term:`lowstate` structures are sent, the Salt
            API will execute them in serial, and will not stop execution upon failure
            of a previous job. If you need to have commands executed in order and
            stop on failure please use compound-command-execution.

        u/loginN(Rwtredirecttdisbatch(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�<sH
cc@s^g}x*|jD]}|j|�s)dS|jdk	rTd|krT|j|d<nd|kp�d|ko�d|ko�d|ks�|jd�Pny4t|dj|d��|�V}|j|�Wqttt	fk
r�|jd�Pqt
k
r.}|jd	j|��tjd
dt
�qXqW|j|ji|d6��|j�dS(
uC
        Disbatch all lowstates to the appropriate clients
        NutokenuusernameupasswordueauthuFailed to authenticateu
_disbatch_{0}uclientu0Unexpected exception while handling request: {0}u,Unexpected exception while handling request:RIureturn(R�R^RsR8RCtgetattrR�RRR	RNRORPR'R[R�R\(RR�R]t	chunk_rettex((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR��s*$
#
c#@s�jdd�s-tjjj�jj�n�d�d<t�j	j
�d�jdd������fd�}g}x:�D]2}||�\}}|j|�|j|�q�W�j��}�j
d|jdd�|jdi��V}d|krPx3|D]+}	y|	jd�Wqtk
r6qXqWtjjd	��nxTtt|d
�t���D]2}||�\}}|j|�|j|�qqWd�|d
D��t�}
|
jt��jjdrtjj�jjd
�}
ntjj�jjd�}tjjj�j�j|d�d|dd�|��fd�}i}
x�tr||g�|
j�s��|
g7�n�fd�}t��V}y1||kr�|�tjj|
��n7||
kr|�s|�tjj|
��nwon|j�}||krD|j|�n|dj d�r�x�|dd
D]}|�krft!�|<qfqfWn^|dd|
|dd<t�|dd<|�r�|
j�r�|�tjj|
��nWqot"k
r�qoXqoWdS(u0
        Dispatch local client commands
        ujidutgtutgt_typeuglobc@sr�jjj�ddj�d|�dtj�}�jjj�ddj�d|�dtj�}||fS(NR5usalt/job/{}/ret/{}ujidR6usyndic/job/{}/ret/{}(RaRcR&R�R R=(tminiontsalt_evtt
syndic_evt(tchunkR(sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytsubscribe_minion�sulocaluargsukwargsuHNo minions matched the target. No command was sent, no jid was assigned.uminionscS@si|]}t|�qS((RQ(t.0tm((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pys
<dictcomp>�s	u
order_mastersusyndic_waitugather_job_timeoutc@std�tj��D��S(u\
            Check if there are any more minions we are waiting on returns from
            cs@s|]}|tkVqdS(N(RQ(R�tx((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pys	<genexpr>�s(tanyRLt
itervalues((Rj(sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt	more_todo�sc@s1x*�D]"}|j�s|jd�qqWdS(N(RRR8(R%(tto_wait(sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pytcancel_inflight_futuress
utagu/newudataureturnuidN((#RXR8RRtjidtgen_jidRaR!R�Rlt
check_minionsRCt_format_call_run_job_asyncRYRRNR(tgentReturnR,RR'tsleepR)R*R+tspawn_callbacktjob_not_runningRRtresultRGR�RQR(RR�R�teventsR�R�R�tf_calltpub_dataRt
min_wait_timetis_finishedR�R�R�tftf_resultt	minion_id((R�RjRR�sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_disbatch_local�s~;+

/

'
	

	

	
cc@s�|jd|d|gd|�V}t|ddgd�}t}xZtr�y�|jjj|d|d|jjd	�}	t|	|g�V}
|
|kr�|	j	�s�|	j
d
�ntj
jt��n|
j�}	Wnqtk
rI|stj
jt��qJ|jd|d|gd|�V}t|ddgd�}t}qEnX|	d
jdi�ikrlqEn|	d
d|kr�t||	d
d<nt}qEWd
S(un
        Return a future which will complete once jid (passed in) is no longer
        running on tgt
        ulocalusaltutil.find_jobttgt_typeujiduretujobR5REugather_job_timeoutudataureturnuidN(RYRRQR'RaRcR&R!RRRR8R(R�R�R�RRX(RR�ttgtR�RjR�t
ping_pub_datatping_tagtminion_runningR%R�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�(s@
	
	

	
cc@sT|j|�}|jd|jdd�|jdi��V}tjj|��dS(u6
        Disbatch local client_async commands
        ulocal_asyncuargsukwargsN((R�RYRXR(R�R�(RR�R�R�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_disbatch_local_asyncTs/cc@s�|jdt�}|jd|�}|dd}yL|jjj|d|�V}|r^|n|dd}tjj|��Wn#t	k
r�tjjd��nXd	S(
u1
        Disbatch runner client commands
        ufull_returnurunnerutagu/retR5udataureturnu%Timeout waiting for runner to executeN(
tpopRQRYRaRcR&R(R�R�R(RR�tfull_returnR�R5R%R�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_disbatch_runner_s
cC@s)|jd|�}tjj|��dS(u7
        Disbatch runner client_async commands
        urunnerN(RYR(R�R�(RR�R�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt_disbatch_runner_asyncpscC@sMtjjjtjjj|dt�}tj	j
j�|jdi�d<|S(Ntis_class_methodukwargsuio_loop(
RRR�tformat_callRdtLocalClienttrun_jobR'R(R)R*R+RX(RR�R�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�zs	"(RRRRXR(twebtasynchronousR�R�t	coroutineR�R�R�R�R�R�R�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�s	&N$z,
tMinionSaltAPIHandlercB@s;eZdZejjdd��Zejjd��ZRS(u=
    A convenience endpoint for minion related functions
    cC@sR|j�s|jd�dSidd6|p0dd6dd6g|_|j�dS(	uH
        A convenience URL for getting lists of minions or getting minion
        details

        .. http:get:: /minions/(mid)

            :reqheader X-Auth-Token: |req_token|
            :reqheader Accept: |req_accept|

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

        **Example request:**

        .. code-block:: bash

            curl -i localhost:8000/minions/ms-3

        .. code-block:: text

            GET /minions/ms-3 HTTP/1.1
            Host: localhost:8000
            Accept: application/x-yaml

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Length: 129005
            Content-Type: application/x-yaml

            return:
            - ms-3:
                grains.items:
                    ...
        u/loginNulocaluclientu*utgtugrains.itemsufun(RwR�R�R�(Rtmid((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRX�s)

cC@s�|j�s|jd�dSxj|jD]_}d|krId|d<q'n|jd�dkr'|jd�|jd�|j�dSq'W|j�dS(ug
        Start an execution command and immediately return the job id

        .. http:post:: /minions

            :reqheader X-Auth-Token: |req_token|
            :reqheader Accept: |req_accept|
            :reqheader Content-Type: |req_ct|

            :resheader Content-Type: |res_ct|

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

            :term:`lowstate` data describing Salt commands must be sent in the
            request body. The ``client`` option will be set to
            :py:meth:`~salt.client.LocalClient.local_async`.

        **Example request:**

        .. code-block:: bash

            curl -sSi localhost:8000/minions \
                -H "Accept: application/x-yaml" \
                -d tgt='*' \
                -d fun='status.diskusage'

        .. code-block:: text

            POST /minions HTTP/1.1
            Host: localhost:8000
            Accept: application/x-yaml
            Content-Length: 26
            Content-Type: application/x-www-form-urlencoded

            tgt=*&fun=status.diskusage

        **Example response:**

        .. code-block:: text

            HTTP/1.1 202 Accepted
            Content-Length: 86
            Content-Type: application/x-yaml

            return:
            - jid: '20130603122505459265'
              minions: [ms-4, ms-3, ms-2, ms-1, ms-0]
        u/loginNuclientulocal_asynci�uWe don't serve your kind here(RwR�R�RXRZR[R\R�(RR]((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR��s5




N(	RRRR(R�R�R8RXR�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR��s	3tJobsSaltAPIHandlercB@s&eZdZejjdd��ZRS(u3
    A convenience endpoint for job cache data
    cC@so|j�s|jd�dS|rGidd6|d6dd6g|_nidd6dd6g|_|j�dS(	u�
        A convenience URL for getting lists of previously run jobs or getting
        the return from a single job

        .. http:get:: /jobs/(jid)

            List jobs or show a single job from the job cache.

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

        **Example request:**

        .. code-block:: bash

            curl -i localhost:8000/jobs

        .. code-block:: text

            GET /jobs HTTP/1.1
            Host: localhost:8000
            Accept: application/x-yaml

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Length: 165
            Content-Type: application/x-yaml

            return:
            - '20121130104633606931':
                Arguments:
                - '3'
                Function: test.fib
                Start Time: 2012, Nov 30 10:46:33.606931
                Target: jerry
                Target-type: glob

        **Example request:**

        .. code-block:: bash

            curl -i localhost:8000/jobs/20121130104633606931

        .. code-block:: text

            GET /jobs/20121130104633606931 HTTP/1.1
            Host: localhost:8000
            Accept: application/x-yaml

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Length: 73
            Content-Type: application/x-yaml

            info:
            - Arguments:
                - '3'
                Function: test.fib
                Minions:
                - jerry
                Start Time: 2012, Nov 30 10:46:33.606931
                Target: '*'
                Target-type: glob
                User: saltdev
                jid: '20121130104633606931'
            return:
            - jerry:
                - - 0
                - 1
                - 1
                - 2
                - 6.9141387939453125e-06
        u/loginNu
jobs.list_jobufunujidurunneruclientujobs.list_jobs(RwR�R�R�(RR�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRXsS
N(RRRR(R�R�R8RX(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�s	tRunSaltAPIHandlercB@s#eZdZejjd��ZRS(uB
    Endpoint to run commands without normal session handling
    cC@s|j�dS(u$
        Run commands bypassing the :ref:`normal session handling
        <rest_cherrypy-auth>`

        .. http:post:: /run

            This entry point is primarily for "one-off" commands. Each request
            must pass full Salt authentication credentials. Otherwise this URL
            is identical to the :py:meth:`root URL (/) <LowDataAdapter.POST>`.

            :term:`lowstate` data describing Salt commands must be sent in the
            request body.

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

        **Example request:**

        .. code-block:: bash

            curl -sS localhost:8000/run \
                -H 'Accept: application/x-yaml' \
                -d client='local' \
                -d tgt='*' \
                -d fun='test.ping' \
                -d username='saltdev' \
                -d password='saltdev' \
                -d eauth='pam'

        .. code-block:: text

            POST /run HTTP/1.1
            Host: localhost:8000
            Accept: application/x-yaml
            Content-Length: 75
            Content-Type: application/x-www-form-urlencoded

            client=local&tgt=*&fun=test.ping&username=saltdev&password=saltdev&eauth=pam

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Length: 73
            Content-Type: application/x-yaml

            return:
            - ms-0: true
                ms-1: true
                ms-2: true
                ms-3: true
                ms-4: true
        N(R�(R((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�rs9(RRRR(R�R�R�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�nstEventsSaltAPIHandlercB@s#eZdZejjd��ZRS(uJ
    Expose the Salt event bus

    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.

    .. seealso:: :ref:`events`
    cc@s�|j�s|jd�dS|jdd�|jdd�|jdd�|jd	jd
��|j�x�tr�yh|jjj	|�V}|jdj|j
dd
���|jtd�jt|���|j�Wqpt
k
r�PqpXqpWdS(u/

        An HTTP stream of the Salt master event bus

        This stream is formatted per the Server Sent Events (SSE) spec. Each
        event is formatted as JSON.

        .. http:get:: /events

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|

        **Example request:**

        .. code-block:: bash

            curl -NsS localhost:8000/events

        .. code-block:: text

            GET /events HTTP/1.1
            Host: localhost:8000

        **Example response:**

        .. code-block:: text

            HTTP/1.1 200 OK
            Connection: keep-alive
            Cache-Control: no-cache
            Content-Type: text/event-stream;charset=utf-8

            retry: 400
            data: {'tag': '', 'data': {'minions': ['ms-4', 'ms-3', 'ms-2', 'ms-1', 'ms-0']}}

            data: {'tag': '20130802115730568475', 'data': {'jid': '20130802115730568475', 'return': True, 'retcode': 0, 'success': True, 'cmd': '_return', 'fun': 'test.ping', 'id': 'ms-1'}}

        The event stream can be easily consumed via JavaScript:

        .. code-block:: javascript

            # Note, you must be authenticated!
            var source = new EventSource('/events');
            source.onopen = function() { console.debug('opening') };
            source.onerror = function(e) { console.debug('error!', e) };
            source.onmessage = function(e) { console.debug(e.data) };

        Or using CORS:

        .. code-block:: javascript

            var source = new EventSource('/events', {withCredentials: true});

        Some browser clients lack CORS support for the ``EventSource()`` API. Such
        clients may instead pass the :mailheader:`X-Auth-Token` value as an URL
        parameter:

        .. code-block:: bash

            curl -NsS localhost:8000/events/6d1b722e

        It is also possible to consume the stream via the shell.

        Records are separated by blank lines; the ``data:`` and ``tag:``
        prefixes will need to be removed manually before attempting to
        unserialize the JSON.

        curl's ``-N`` flag turns off input buffering which is required to
        process the stream incrementally.

        Here is a basic example of printing each event as it comes in:

        .. code-block:: bash

            curl -NsS localhost:8000/events |\
                    while IFS= read -r line ; do
                        echo $line
                    done

        Here is an example of using awk to filter events based on tag:

        .. code-block:: bash

            curl -NsS localhost:8000/events |\
                    awk '
                        BEGIN { RS=""; FS="\\n" }
                        $1 ~ /^tag: salt\/job\/[0-9]+\/new$/ { print $0 }
                    '
            tag: salt/job/20140112010149808995/new
            data: {"tag": "salt/job/20140112010149808995/new", "data": {"tgt_type": "glob", "jid": "20140112010149808995", "tgt": "jerry", "_stamp": "2014-01-12_01:01:49.809617", "user": "shouse", "arg": [], "fun": "test.ping", "minions": ["jerry"]}}
            tag: 20140112010149808995
            data: {"tag": "20140112010149808995", "data": {"fun_args": [], "jid": "20140112010149808995", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2014-01-12_01:01:49.819316", "fun": "test.ping", "id": "jerry"}}
        u/loginNuContent-Typeutext/event-streamu
Cache-Controluno-cacheu
Connectionu
keep-aliveuretry: {0}
i�u	tag: {0}
utaguudata: {0}

(RwR�R�R[R�tflushR'RaRcR&RXtstrRR(RR%((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyRX�s `

	""
(RRRR(R�R�RX(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR��s
tWebhookSaltAPIHandlercB@seZdZdd�ZRS(u�
    A generic web hook entry point that fires an event on Salt's event bus

    External services can POST data to this URL to trigger an event in Salt.
    For example, Amazon SNS, Jenkins-CI or Travis-CI, or GitHub web hooks.

    .. note:: Be mindful of security

        Salt's Reactor can run any code. A Reactor SLS that responds to a hook
        event is responsible for validating that the event came from a trusted
        source and contains valid data.

        **This is a generic interface and securing it is up to you!**

        This URL requires authentication however not all external services can
        be configured to authenticate. For this reason authentication can be
        selectively disabled for this URL. Follow best practices -- always use
        SSL, pass a secret key, configure the firewall to only allow traffic
        from a known source, etc.

    The event data is taken from the request body. The
    :mailheader:`Content-Type` header is respected for the payload.

    The event tag is prefixed with ``salt/netapi/hook`` and the URL path is
    appended to the end. For example, a ``POST`` request sent to
    ``/hook/mycompany/myapp/mydata`` will produce a Salt event with the tag
    ``salt/netapi/hook/mycompany/myapp/mydata``.

    The following is an example ``.travis.yml`` file to send notifications to
    Salt of successful test runs:

    .. code-block:: yaml

        language: python
        script: python -m unittest tests
        after_success:
            - 'curl -sS http://saltapi-url.example.com:8000/hook/travis/build/success -d branch="${TRAVIS_BRANCH}" -d commit="${TRAVIS_COMMIT}"'

    .. seealso:: :ref:`events`, :ref:`reactor`
    c	C@sF|jjjd�}|r:|j�r:|jd�dSd}|rS||7}ntjjjd|jj	d|jj	dd|jj	d	t
�|_i}xL|jjD]>}|j
|�}t|�d
kr�|d}n|||<q�W|jji|jd6|d
6t|jj�d6|�}|j|ji|d6��dS(u

        Fire an event in Salt with a custom event tag and data

        .. http:post:: /hook

            :status 200: |200|
            :status 401: |401|
            :status 406: |406|
            :status 413: request body is too large

        **Example request:**

        .. code-block:: bash

            curl -sS localhost:8000/hook -d foo='Foo!' -d bar='Bar!'

        .. code-block:: text

            POST /hook HTTP/1.1
            Host: localhost:8000
            Content-Length: 16
            Content-Type: application/x-www-form-urlencoded

            foo=Foo&bar=Bar!

        **Example response**:

        .. code-block:: text

            HTTP/1.1 200 OK
            Content-Length: 14
            Content-Type: application/json

            {"success": true}

        As a practical example, an internal continuous-integration build
        server could send an HTTP POST request to the URL
        ``http://localhost:8000/hook/mycompany/build/success`` which contains
        the result of a build and the SHA of the version that was built as
        JSON. That would then produce the following event in Salt that could be
        used to kick off a deployment via Salt's Reactor:

        .. code-block:: text

            Event fired at Fri Feb 14 17:40:11 2014
            *************************
            Tag: salt/netapi/hook/mycompany/build/success
            Data:
            {'_stamp': '2014-02-14_17:40:11.440996',
                'headers': {
                    'X-My-Secret-Key': 'F0fAgoQjIT@W',
                    'Content-Length': '37',
                    'Content-Type': 'application/json',
                    'Host': 'localhost:8000',
                    'Remote-Addr': '127.0.0.1'},
                'post': {'revision': 'aa22a3c4b2e7', 'result': True}}

        Salt's Reactor could listen for the event:

        .. code-block:: yaml

            reactor:
              - 'salt/netapi/hook/mycompany/build/*':
                - /srv/reactor/react_ci_builds.sls

        And finally deploy the new build:

        .. code-block:: jinja

            {% set secret_key = data.get('headers', {}).get('X-My-Secret-Key') %}
            {% set build = data.get('post', {}) %}

            {% if secret_key == 'F0fAgoQjIT@W' and build.result == True %}
            deploy_my_app:
              cmd.state.sls:
                - tgt: 'application*'
                - arg:
                  - myapp.deploy
                - kwarg:
                    pillar:
                      revision: {{ revision }}
            {% endif %}
        uwebhook_disable_authu/loginNusalt/netapi/hookumasterusock_diru	transportR!R"iiupostugetuheadersusuccess(RaR$RXRwR�RRR%R&R!RQR4tquery_argumentsR�RHt
fire_eventR�R�RpR[R�(Rt
tag_suffixtdisable_authR5R�targnameR�R�((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR�Ws2T




	N(RRRR8R�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR.s(cC@sFt|t�r"||krB|Sn |dkr2|S||krB|SdS(u7
    Check if an origin match cors allowed origins
    u*N(R�R,(R�tallowed_origins((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyR��s(BRt
__future__RRRR�RytloggingRtcollectionsRR�ttornado.escapeR(ttornado.httpserverttornado.ioloopttornado.webttornado.genttornado.concurrentRtsalt.ext.sixtextRLtsalt.netapiRtsalt.utils.argstsalt.utils.eventtsalt.utils.jsontsalt.utils.minionstsalt.utils.yamltsalt.utils.zeromqRtsalt.clienttsalt.runnert	salt.authtsalt.exceptionsRRR	Rtzeromqtinstall_zmqR
timport_jsont	getLoggerRRORRoRrRNRRtobjectR R�tRequestHandlerRWR�R�R�R�R�R�RR�(((sE/usr/lib/python2.7/site-packages/salt/netapi/rest_tornado/saltnado.pyt<module>�sZ	����r�j@��

Zerion Mini Shell 1.0