• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H25-Aug-2020-6246

crossplane/H25-Aug-2020-3,3382,986

ext/H03-May-2022-

tests/H25-Aug-2020-2,2832,095

.gitignoreH A D25-Aug-20201.9 KiB171158

.travis.ymlH A D25-Aug-2020265 1716

AUTHORS.rstH A D25-Aug-2020639 1713

CODE_OF_CONDUCT.mdH A D25-Aug-20203.2 KiB7556

CONTRIBUTING.mdH A D25-Aug-20202.9 KiB11069

LICENSEH A D25-Aug-20209.9 KiB177150

MANIFEST.inH A D25-Aug-202099 43

MakefileH A D25-Aug-20201.1 KiB4032

NOTICEH A D25-Aug-2020639 1912

README.mdH A D25-Aug-202015.1 KiB524419

setup.pyH A D25-Aug-20202.5 KiB9473

tox.iniH A D25-Aug-2020620 2319

README.md

1![Crossplane Logo](https://raw.githubusercontent.com/nginxinc/crossplane/master/ext/crossplane-logo.png)
2<h1 align="center">crossplane</h1>
3<h3 align="center">Reliable and fast NGINX configuration file parser and builder</h3>
4
5<p align="center">
6<a href="https://travis-ci.org/nginxinc/crossplane"><img src="https://img.shields.io/travis/nginxinc/crossplane/master.svg"></a>
7<a href="https://github.com/nginxinc/crossplane/releases"><img src="https://img.shields.io/github/release/nginxinc/crossplane.svg"></a>
8<a href="https://pypi.python.org/pypi/crossplane"><img src="https://img.shields.io/pypi/l/crossplane.svg"></a>
9<a href="https://pypi.python.org/pypi/crossplane"><img src="https://img.shields.io/pypi/pyversions/crossplane.svg"></a>
10</p>
11
12  - [Install](#install)
13  - [Command Line Interface](#command-line-interface)
14      - [crossplane parse](#crossplane-parse)
15      - [crossplane build](#crossplane-build)
16      - [crossplane lex](#crossplane-lex)
17      - [crossplane format](#crossplane-format)
18      - [crossplane minify](#crossplane-minify)
19  - [Python Module](#python-module)
20      - [crossplane.parse()](#crossplaneparse)
21      - [crossplane.build()](#crossplanebuild)
22      - [crossplane.lex()](#crossplanelex)
23  - [Other Languages](#other-languages)
24
25## Install
26
27You can install both the [Command Line
28Interface](#command-line-interface) and [Python Module](#python-module)
29via:
30
31    pip install crossplane
32
33## Command Line Interface
34
35```
36usage: crossplane <command> [options]
37
38various operations for nginx config files
39
40optional arguments:
41  -h, --help            show this help message and exit
42  -V, --version         show program's version number and exit
43
44commands:
45  parse                 parses a json payload for an nginx config
46  build                 builds an nginx config from a json payload
47  lex                   lexes tokens from an nginx config file
48  minify                removes all whitespace from an nginx config
49  format                formats an nginx config file
50  help                  show help for commands
51```
52
53### crossplane parse
54
55This command will take a path to a main NGINX config file as input, then
56parse the entire config into the schema defined below, and dumps the
57entire thing as a JSON payload.
58
59```
60usage: crossplane parse [-h] [-o OUT] [-i NUM] [--ignore DIRECTIVES]
61                        [--no-catch] [--tb-onerror] [--single-file]
62                        [--include-comments] [--strict]
63                        filename
64
65parses a json payload for an nginx config
66
67positional arguments:
68  filename              the nginx config file
69
70optional arguments:
71  -h, --help            show this help message and exit
72  -o OUT, --out OUT     write output to a file
73  -i NUM, --indent NUM  number of spaces to indent output
74  --ignore DIRECTIVES   ignore directives (comma-separated)
75  --no-catch            only collect first error in file
76  --tb-onerror          include tracebacks in config errors
77  --combine             use includes to create one single file
78  --single-file         do not include other config files
79  --include-comments    include comments in json
80  --strict              raise errors for unknown directives
81```
82
83**Privacy and Security**
84
85Since `crossplane` is usually used to create payloads that are sent to
86different servers, it's important to keep security in mind. For that
87reason, the `--ignore` option was added. It can be used to keep certain
88sensitive directives out of the payload output entirely.
89
90For example, we always use the equivalent of this flag in the [NGINX Amplify
91Agent](https://github.com/nginxinc/nginx-amplify-agent/) out of respect
92for our users'
93    privacy:
94
95    --ignore=auth_basic_user_file,secure_link_secret,ssl_certificate_key,ssl_client_certificate,ssl_password_file,ssl_stapling_file,ssl_trusted_certificate
96
97#### Schema
98
99**Response Object**
100
101```js
102{
103    "status": String, // "ok" or "failed" if "errors" is not empty
104    "errors": Array,  // aggregation of "errors" from Config objects
105    "config": Array   // Array of Config objects
106}
107```
108
109**Config Object**
110
111```js
112{
113    "file": String,   // the full path of the config file
114    "status": String, // "ok" or "failed" if errors is not empty array
115    "errors": Array,  // Array of Error objects
116    "parsed": Array   // Array of Directive objects
117}
118```
119
120**Directive Object**
121
122```js
123{
124    "directive": String, // the name of the directive
125    "line": Number,      // integer line number the directive started on
126    "args": Array,       // Array of String arguments
127    "includes": Array,   // Array of integers (included iff this is an include directive)
128    "block": Array       // Array of Directive Objects (included iff this is a block)
129}
130```
131
132<div class="note">
133
134<div class="admonition-title">
135
136Note
137
138</div>
139
140If this is an `include` directive and the `--single-file` flag was not
141used, an `"includes"` value will be used that holds an Array of indices
142of the configs that are included by this directive.
143
144If this is a block directive, a `"block"` value will be used that holds
145an Array of more Directive Objects that define the block context.
146
147</div>
148
149**Error Object**
150
151```js
152{
153    "file": String,     // the full path of the config file
154    "line": Number,     // integer line number the directive that caused the error
155    "error": String,    // the error message
156    "callback": Object  // only included iff an "onerror" function was passed to parse()
157}
158```
159
160<div class="note">
161
162<div class="admonition-title">
163
164Note
165
166</div>
167
168If the `--tb-onerror` flag was used by crossplane parse, `"callback"`
169will contain a string that represents the traceback that the error
170caused.
171
172</div>
173
174#### Example
175
176The main NGINX config file is at `/etc/nginx/nginx.conf`:
177
178```nginx
179events {
180    worker_connections 1024;
181}
182
183http {
184    include conf.d/*.conf;
185}
186```
187
188And this config file is at `/etc/nginx/conf.d/servers.conf`:
189
190```nginx
191server {
192    listen 8080;
193    location / {
194        try_files 'foo bar' baz;
195    }
196}
197
198server {
199    listen 8081;
200    location / {
201        return 200 'success!';
202    }
203}
204```
205
206So then if you run this:
207
208    crossplane parse --indent=4 /etc/nginx/nginx.conf
209
210The prettified JSON output would look like this:
211
212```js
213{
214    "status": "ok",
215    "errors": [],
216    "config": [
217        {
218            "file": "/etc/nginx/nginx.conf",
219            "status": "ok",
220            "errors": [],
221            "parsed": [
222                {
223                    "directive": "events",
224                    "line": 1,
225                    "args": [],
226                    "block": [
227                        {
228                            "directive": "worker_connections",
229                            "line": 2,
230                            "args": [
231                                "1024"
232                            ]
233                        }
234                    ]
235                },
236                {
237                    "directive": "http",
238                    "line": 5,
239                    "args": [],
240                    "block": [
241                        {
242                            "directive": "include",
243                            "line": 6,
244                            "args": [
245                                "conf.d/*.conf"
246                            ],
247                            "includes": [
248                                1
249                            ]
250                        }
251                    ]
252                }
253            ]
254        },
255        {
256            "file": "/etc/nginx/conf.d/servers.conf",
257            "status": "ok",
258            "errors": [],
259            "parsed": [
260                {
261                    "directive": "server",
262                    "line": 1,
263                    "args": [],
264                    "block": [
265                        {
266                            "directive": "listen",
267                            "line": 2,
268                            "args": [
269                                "8080"
270                            ]
271                        },
272                        {
273                            "directive": "location",
274                            "line": 3,
275                            "args": [
276                                "/"
277                            ],
278                            "block": [
279                                {
280                                    "directive": "try_files",
281                                    "line": 4,
282                                    "args": [
283                                        "foo bar",
284                                        "baz"
285                                    ]
286                                }
287                            ]
288                        }
289                    ]
290                },
291                {
292                    "directive": "server",
293                    "line": 8,
294                    "args": [],
295                    "block": [
296                        {
297                            "directive": "listen",
298                            "line": 9,
299                            "args": [
300                                "8081"
301                            ]
302                        },
303                        {
304                            "directive": "location",
305                            "line": 10,
306                            "args": [
307                                "/"
308                            ],
309                            "block": [
310                                {
311                                    "directive": "return",
312                                    "line": 11,
313                                    "args": [
314                                        "200",
315                                        "success!"
316                                    ]
317                                }
318                            ]
319                        }
320                    ]
321                }
322            ]
323        }
324    ]
325}
326```
327
328#### crossplane parse (advanced)
329
330This tool uses two flags that can change how `crossplane` handles
331errors.
332
333The first, `--no-catch`, can be used if you'd prefer that crossplane
334quit parsing after the first error it finds.
335
336The second, `--tb-onerror`, will add a `"callback"` key to all error
337objects in the JSON output, each containing a string representation of
338the traceback that would have been raised by the parser if the exception
339had not been caught. This can be useful for logging purposes.
340
341### crossplane build
342
343This command will take a path to a file as input. The file should
344contain a JSON representation of an NGINX config that has the structure
345defined above. Saving and using the output from `crossplane parse` to
346rebuild your config files should not cause any differences in content
347except for the formatting.
348
349```
350usage: crossplane build [-h] [-d PATH] [-f] [-i NUM | -t] [--no-headers]
351                        [--stdout] [-v]
352                        filename
353
354builds an nginx config from a json payload
355
356positional arguments:
357  filename              the file with the config payload
358
359optional arguments:
360  -h, --help            show this help message and exit
361  -v, --verbose         verbose output
362  -d PATH, --dir PATH   the base directory to build in
363  -f, --force           overwrite existing files
364  -i NUM, --indent NUM  number of spaces to indent output
365  -t, --tabs            indent with tabs instead of spaces
366  --no-headers          do not write header to configs
367  --stdout              write configs to stdout instead
368```
369
370### crossplane lex
371
372This command takes an NGINX config file, splits it into tokens by
373removing whitespace and comments, and dumps the list of tokens as a JSON
374array.
375
376```
377usage: crossplane lex [-h] [-o OUT] [-i NUM] [-n] filename
378
379lexes tokens from an nginx config file
380
381positional arguments:
382  filename              the nginx config file
383
384optional arguments:
385  -h, --help            show this help message and exit
386  -o OUT, --out OUT     write output to a file
387  -i NUM, --indent NUM  number of spaces to indent output
388  -n, --line-numbers    include line numbers in json payload
389```
390
391#### Example
392
393Passing in this NGINX config file at `/etc/nginx/nginx.conf`:
394
395```nginx
396events {
397    worker_connections 1024;
398}
399
400http {
401    include conf.d/*.conf;
402}
403```
404
405By running:
406
407    crossplane lex /etc/nginx/nginx.conf
408
409Will result in this JSON
410output:
411
412```js
413["events","{","worker_connections","1024",";","}","http","{","include","conf.d/*.conf",";","}"]
414```
415
416However, if you decide to use the `--line-numbers` flag, your output
417will look
418like:
419
420```js
421[["events",1],["{",1],["worker_connections",2],["1024",2],[";",2],["}",3],["http",5],["{",5],["include",6],["conf.d/*.conf",6],[";",6],["}",7]]
422```
423
424### crossplane format
425
426This is a quick and dirty tool that uses [crossplane
427parse](#crossplane-parse) internally to format an NGINX config file.
428It serves the purpose of demonstrating what you can do with `crossplane`'s
429parsing abilities. It is not meant to be a fully fleshed out, feature-rich
430formatting tool. If that is what you are looking for, then you may want to
431look writing your own using crossplane's Python API.
432
433```
434usage: crossplane format [-h] [-o OUT] [-i NUM | -t] filename
435
436formats an nginx config file
437
438positional arguments:
439  filename              the nginx config file
440
441optional arguments:
442  -h, --help            show this help message and exit
443  -o OUT, --out OUT     write output to a file
444  -i NUM, --indent NUM  number of spaces to indent output
445  -t, --tabs            indent with tabs instead of spaces
446```
447
448### crossplane minify
449
450This is a simple and fun little tool that uses [crossplane
451lex](#crossplane-lex) internally to remove as much whitespace from an
452NGINX config file as possible without affecting what it does. It can't
453imagine it will have much of a use to most people, but it demonstrates
454the kinds of things you can do with `crossplane`'s lexing abilities.
455
456```
457usage: crossplane minify [-h] [-o OUT] filename
458
459removes all whitespace from an nginx config
460
461positional arguments:
462  filename           the nginx config file
463
464optional arguments:
465  -h, --help         show this help message and exit
466  -o OUT, --out OUT  write output to a file
467```
468
469## Python Module
470
471In addition to the command line tool, you can import `crossplane` as a
472python module. There are two basic functions that the module will
473provide you: `parse` and `lex`.
474
475### crossplane.parse()
476
477```python
478import crossplane
479payload = crossplane.parse('/etc/nginx/nginx.conf')
480```
481
482This will return the same payload as described in the [crossplane
483parse](#crossplane-parse) section, except it will be Python dicts and
484not one giant JSON string.
485
486### crossplane.build()
487
488```python
489import crossplane
490config = crossplane.build(
491    [{
492        "directive": "events",
493        "args": [],
494        "block": [{
495            "directive": "worker_connections",
496            "args": ["1024"]
497        }]
498    }]
499)
500```
501
502This will return a single string that contains an entire NGINX config
503file.
504
505### crossplane.lex()
506
507```python
508import crossplane
509tokens = crossplane.lex('/etc/nginx/nginx.conf')
510```
511
512`crossplane.lex` generates 2-tuples. Inserting these pairs into a list
513will result in a long list similar to what you can see in the
514[crossplane lex](#crossplane-lex) section when the `--line-numbers` flag
515is used, except it will obviously be a Python list of tuples and not one
516giant JSON string.
517
518## Other Languages
519
520- Go port by [@aluttik](https://github.com/aluttik):
521    <https://github.com/aluttik/go-crossplane>
522- Ruby port by [@gdanko](https://github.com/gdanko):
523    <https://github.com/gdanko/crossplane>
524