Wiki » History » Version 1
Redmine Admin, 01/04/2017 04:48 PM
1 | 1 | Redmine Admin | {{toc}} |
---|---|---|---|
2 | |||
3 | h1. Services on LINDAT |
||
4 | |||
5 | # Proxies setup |
||
6 | |||
7 | I took a liberty to reorganize the way we define the proxies. Each proxy setup has a separate file. All definitions related to that proxy should be in that file and not anywhere else. The proxies definitions are in the directory `proxies-available` and enabled proxies are symlinked in `proxies-enabled`. |
||
8 | |||
9 | You don't have to do symlinks by hand, but you can use `config_proxies.sh` [script](https://gist.github.com/m1ch4ls/0f5444a8f2d1e06693a4). |
||
10 | |||
11 | |||
12 | ``` |
||
13 | . |
||
14 | ├── config_proxies.sh |
||
15 | ├── proxies-available |
||
16 | │ ├── cesilko |
||
17 | │ ├── .... |
||
18 | │ ├── pmltq |
||
19 | │ └── treex-web |
||
20 | ├── proxies-enabled |
||
21 | ... |
||
22 | ``` |
||
23 | |||
24 | # Add new proxy |
||
25 | |||
26 | The file skeleton: |
||
27 | |||
28 | ```nginx |
||
29 | # who is responsible |
||
30 | |||
31 | |||
32 | location /services/name { |
||
33 | rewrite /services/name(.*) /proxied/path$1 brea |
||
34 | |||
35 | include service_prox |
||
36 | proxy_pass http://ques |
||
37 | } |
||
38 | ``` |
||
39 | |||
40 | ## `location` |
||
41 | |||
42 | The crucial directive here is `location` see [Nginx documentation for details](http://nginx.org/en/docs/http/ngx_http_core_module.html#location). |
||
43 | |||
44 | The most important part is the way how are the locations matched to urls and which location gets used. |
||
45 | |||
46 | 1. Exact match (note `=`) |
||
47 | ```nginx |
||
48 | location = /services/exact { ... } |
||
49 | ``` |
||
50 | If the exact match is found the matching process is terminated and the matched location is used. |
||
51 | |||
52 | 2. The longest matching prefix |
||
53 | ```nginx |
||
54 | location /services/name { config A } |
||
55 | location /services/name/images { config B } |
||
56 | ``` |
||
57 | The longest matching prefix is selected and than the matching continues ... |
||
58 | |||
59 | 3. Regular expressions are checked after looking for the longest prefix |
||
60 | ```nginx |
||
61 | # case-sensitive match |
||
62 | location ~ \.(gif)$ { } |
||
63 | # case-insensitive match |
||
64 | location ~* \.(php)$ { } |
||
65 | ``` |
||
66 | Regular expressions are checked in the order they appear in the config file. If the regular expression match the first one is used. If not the longest matching substring is used instead. |
||
67 | |||
68 | 4. To get things even more complicated you can use `^~` operator to match the longest prefix and don't do regular expression search. This works in similar way the `=` works. |
||
69 | |||
70 | ## `rewrite` |
||
71 | |||
72 | Use `rewrite` to change base url if required. [See documentation for details](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite). |
||
73 | |||
74 | ## `proxy_pass` |
||
75 | |||
76 | Every location defined for service should end with `proxy_pass`. It's recommended to use `include service_prox` to inject useful headers to service endpoint. |
||
77 | |||
78 | The endpoint definition can be full url or so called `upstream`. The upstreams defined: |
||
79 | |||
80 | - quest |
||
81 | - apache |
||
82 | - tomcats |
||
83 | |||
84 | You can't define `upstream` in service file because it's not included in the context where `upstream` definition is allowed. |
||
85 | |||
86 | [See documentation](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) for more details. |
||
87 | |||
88 | # Shibboleth authentication |
||
89 | |||
90 | Shibboleth authentication only works for `https`. To make things as simple as possible I have made a file you can include to make Shibboleth work out of the box. Otherwise those directives would have to be repeated everytime. |
||
91 | |||
92 | ```nginx |
||
93 | more_clear_input_headers 'Variable-*' 'Shib-*' 'Remote-User' 'REMOTE_USER' 'Auth-Type' 'AUTH_TYPE\r |
||
94 | |||
95 | # Add your attributes here. They get introduced as headers |
||
96 | # by the FastCGI authorizer so we must prevent spoofing. |
||
97 | more_clear_input_headers 'displayName' 'mail' 'persistent-id\r |
||
98 | |||
99 | # Require https and will redirect |
||
100 | if ($https != "on") { |
||
101 | return 301 https://$http_host$request_ur |
||
102 | } |
||
103 | |||
104 | shib_request /shibauthorize |
||
105 | ``` |
||
106 | |||
107 | Instead use `include shibboleth_aut`. |
||
108 | |||
109 | Example: |
||
110 | |||
111 | ```nginx |
||
112 | location = /services/name/shibboleth-login-url { |
||
113 | include shibboleth_aut |
||
114 | |||
115 | rewrite /services/name(.*) /proxied/path$1 brea |
||
116 | |||
117 | include service_prox |
||
118 | proxy_pass http://ques |
||
119 | } |
||
120 | ``` |
||
121 | |||
122 | Note the `=` in `location` directive. This will ensure that Shibboleth authentication will trigger only for this location. |
||
123 | |||
124 | h1. Python REST |
||
125 | |||
126 | Python REST is an implementation of REST (Representational State Transfer) like server written in Python. The python REST server is being implemented by UFAL. The main objectives of this implementation are, |
||
127 | |||
128 | * to provide a consistent web based interaction to the already available and future NLP tools developed at UFAL. |
||
129 | * to aid the web developers by providing them GET/POST like API methods that can be used to access the NLP tools. |
||
130 | * to aid the NLP tools developers at UFAL to easily port their stand alone applications to web. |
||
131 | |||
132 | h1. How to use Python REST |
||
133 | |||
134 | h2. Clone the REST repository |
||
135 | |||
136 | The REST server can be run from any machine that supports Python. The REST can made available to the local machine by cloning the source code repository. To clone the repository, you need the @Git@ software. Use the following @Git@ command to populate the repository locally, |
||
137 | |||
138 | <pre> |
||
139 | git clone gitolite@redmine.ms.mff.cuni.cz:lindat/lindat-services.git REST |
||
140 | </pre> |
||
141 | |||
142 | Once the repository is cloned to the REST directory, you will be able to see the following files under the cloned repository, |
||
143 | |||
144 | <pre> |
||
145 | $ cd REST |
||
146 | $ ls -F |
||
147 | applications/ nohup.out pyrest@ settings/ |
||
148 | cherrypy/ project_settings.py README utils.py |
||
149 | logs/ project_settings.pyc _scripts/ utils.pyc |
||
150 | main.py* project_settings.py.example server/ |
||
151 | </pre> |
||
152 | |||
153 | h2. Run the REST server |
||
154 | |||
155 | To start the REST service, you need to do two major things, |
||
156 | |||
157 | * *Server Settings* |
||
158 | * *Expose Plugins* |
||
159 | |||
160 | |||
161 | h3. *Server settings* |
||
162 | |||
163 | ** at least set the server name and port number in which the REST server should run. |
||
164 | |||
165 | The server settings should be added to the file @project_settings.py@ at the top-level directory. |
||
166 | The minimum settings for the REST service is given below, copy the following contents into @project_settings.py@ |
||
167 | |||
168 | <pre> |
||
169 | # coding=utf-8 |
||
170 | # See main file for licence |
||
171 | |||
172 | """ |
||
173 | Project specific settings overriding the default ones in `settings` directory. |
||
174 | """ |
||
175 | |||
176 | settings = { |
||
177 | |||
178 | "server": { |
||
179 | "host": "127.0.0.1", |
||
180 | "port": 8280, |
||
181 | } |
||
182 | } |
||
183 | </pre> |
||
184 | |||
185 | |||
186 | h3. *Expose an application/service to web via REST plugins* |
||
187 | |||
188 | A plugin is a piece of code written in Python (in our case) that interacts with the actual application. The plugin acts as a middle layer that accepts requests from the web and passes the requests to the actual application for processing. Also, the plugin is responsible for obtaining the results returned by the application to the web clients. A plugin essentially processes external HTTP requests for a particular exposed application/service (for example: the NLP application Cesilko) and communicates the results of the application back to the HTTP clients. The plugin offers list of APIs which the HTTP clients can request through HTTP methods (such as GET, POST, DELETE and PUT). |
||
189 | |||
190 | ** Each plugin defines list of APIs the REST should expose to the outside world for a particular application/service. |
||
191 | ** Each plugin defines methods for processing the API requests and return the output in JSON format. |
||
192 | |||
193 | |||
194 | There's simple plugin in the @applications/expose_myservice.py@. The @applications/expose_myservice.py@ defines the following things, |
||
195 | |||
196 | * The name of the service : *myservice* |
||
197 | * Provides List of APIs: |
||
198 | |||
199 | |_.# |_. API name |_. API parameters | |
||
200 | | 1 | *myapi* | "list" (required) | |
||
201 | | 2 | *version* | | |
||
202 | |||
203 | |||
204 | h3. Start the REST server |
||
205 | |||
206 | <pre> |
||
207 | python pyrest |
||
208 | or |
||
209 | python main.py |
||
210 | </pre> |
||
211 | |||
212 | |||
213 | h3. Accessing the REST service APIs |
||
214 | |||
215 | Once the REST server is started, the applications (via plugins in the directory @applications/@) will be exposed via the port as defined in the @project_settings.py@. Then, the applications/services can be accessed via HTTP requests. The examples below show how to access the API methods as defined in @applications/expose_myservice.py@ via HTTP requests. |
||
216 | |||
217 | |||
218 | h4. *"myapi"* |
||
219 | |||
220 | <pre> |
||
221 | http://127.0.0.1:8280/myservice/myapi?list=hello |
||
222 | </pre> |
||
223 | |||
224 | The expected output for the above API request should be, |
||
225 | |||
226 | <pre> |
||
227 | { |
||
228 | "input": "hello", |
||
229 | "result": "this is an example" |
||
230 | } |
||
231 | </pre> |
||
232 | |||
233 | |||
234 | h4. *"version"* |
||
235 | |||
236 | <pre> |
||
237 | http://127.0.0.1:8280/myservice/version |
||
238 | </pre> |
||
239 | |||
240 | The expected output for the above API request should be, |
||
241 | |||
242 | <pre> |
||
243 | { |
||
244 | "version": "myservice version 1" |
||
245 | } |
||
246 | </pre> |
||
247 | |||
248 | |||
249 | h3. API output format |
||
250 | |||
251 | At present, the Python REST supports only "JSON":http://en.wikipedia.org/wiki/JSON format. All HTTP GET/POST requests to REST services will be returned via JSON objects. JSON is supported by all web tools, so that the outputs can be used by API developers or others who want to get access to the REST services through web programming tools. |
||
252 | |||
253 | h1. Detailed Documentation on Python REST |
||
254 | |||
255 | Here you can read more about the Python REST and how to define/expose your own applications via plugins: [[Python REST detailed documentation]] |
||
256 | |||
257 | h1. Step-by-Step guide to adding LINDAT/CLARIN service |
||
258 | |||
259 | h2. [[Cesilko]] |