├── .gitignore ├── LICENSE.md ├── README.md ├── hiera.yaml ├── hosts ├── macros ├── apache_encode_macro.erb ├── apache_encode_macro.j2 ├── erlang_encode_macro.erb ├── erlang_encode_macro.j2 ├── ini_encode_macro.erb ├── ini_encode_macro.j2 ├── json_encode_macro.erb ├── json_encode_macro.j2 ├── logstash_encode_macro.erb ├── logstash_encode_macro.j2 ├── toml_encode_macro.erb ├── toml_encode_macro.j2 ├── xml_encode_macro.erb ├── xml_encode_macro.j2 ├── yaml_encode_macro.erb └── yaml_encode_macro.j2 ├── puppet_apply.sh ├── site.pp ├── site.yaml ├── templates ├── test.apache.erb ├── test.apache.j2 ├── test.erlang.erb ├── test.erlang.j2 ├── test.ini.erb ├── test.ini.j2 ├── test.ini_simple.erb ├── test.ini_simple.j2 ├── test.json.erb ├── test.json.j2 ├── test.logstash.erb ├── test.logstash.j2 ├── test.toml.erb ├── test.toml.j2 ├── test.xml.erb ├── test.xml.j2 ├── test.yaml.erb └── test.yaml.j2 ├── vars ├── apache_test.yaml ├── erlang_test.yaml ├── ini_test.yaml ├── json_test.yaml ├── logstash_test.yaml ├── toml_test.yaml ├── xml_test.yaml └── yaml_test.yaml ├── yaml_converter.py └── yaml_converter.rb /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/picotrading/config-encoder-macros/624ed05b65743a82bcfdef525176e6cfef5c71ee/.gitignore -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Jiri Tyr 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Config Encoder Macros 2 | ===================== 3 | 4 | Set of Jinja2 and ERB macros which help to encode Python and Ruby data structure 5 | into a different file format. 6 | 7 | 8 | --- 9 | 10 | * [Motivation](#motivation) 11 | * [Supported formats](#supported-formats) 12 | * Examples 13 | * [Ansible example](#ansible-example) 14 | * [Puppet example](#puppet-example) 15 | * [Macros parameters](#macros-parameters) 16 | * [Limitations](#limitations) 17 | * Programming support 18 | * [Python example](#python-example) 19 | * [Ruby example](#ruby-example) 20 | * [License](#license) 21 | * [Author](#author) 22 | 23 | --- 24 | 25 | 26 | Motivation 27 | ---------- 28 | 29 | The motivation to create these macros was to be able to create an universal 30 | description of configuration files in [Ansible](http://ansible.com). Ansible and 31 | Puppet is using YAML format as the main data input. This format allows to 32 | describe almost any structure of a configuration file. Ansible resp. Puppet 33 | converts the YAML data into a Python resp. Ruby data structure using primitive 34 | data types (e.g. `dict`, `list`, `string`, `number`, `boolean`, ...). That data 35 | structure is then used in Jinja2 and ERB template files to produce the final 36 | configuration file. The encoder macros are used to convert the Python or Ruby 37 | data structure to another format. 38 | 39 | 40 | Supported formats 41 | ----------------- 42 | 43 | - Apache config format 44 | - Erlang config format 45 | - INI 46 | - JSON 47 | - Logstash 48 | - TOML 49 | - XML 50 | - YAML 51 | 52 | 53 | Ansible example 54 | --------------- 55 | 56 | Clone this repo into the `templates` directory in the playbook location: 57 | 58 | ``` 59 | $ git clone https://github.com/picotrading/config-encoder-macros ./templates/encoder 60 | ``` 61 | 62 | Then use the macros in your playbook (e.g. `site.yaml`) like this: 63 | 64 | ``` 65 | # Playbook example 66 | - name: Play to test the encoder macros 67 | hosts: all 68 | vars: 69 | ini_data: 70 | var1: val1 71 | var2: val2 72 | section1: 73 | aaa: asdf 74 | bbb: 123 75 | ccc: 'true' 76 | section2: 77 | ddd: asdfasd 78 | eee: 1234 79 | fff: 'false' 80 | tasks: 81 | - name: Create test.ini file 82 | template: 83 | src: templates/test.ini.j2 84 | dest: /tmp/test.ini 85 | ``` 86 | 87 | Where the `templates/test.ini.j2` contains: 88 | 89 | ``` 90 | # 91 | # This file is managed by Ansible. 92 | # Do not edit this file manually. 93 | # Any changes will be automatically reverted. 94 | # 95 | 96 | {% from "templates/encoder/macros/ini_encode_macro.j2" import ini_encode with context -%} 97 | 98 | {{ ini_encode(ini_data) }} 99 | ``` 100 | 101 | And if you call the playbook: 102 | 103 | ``` 104 | $ ansible-playbook -i hosts ./site.yaml 105 | ``` 106 | 107 | You get the following in the `/tmp/test.ini`: 108 | 109 | ``` 110 | # 111 | # This file is managed by Ansible. 112 | # Do not edit this file manually. 113 | # Any changes will be automatically reverted. 114 | # 115 | 116 | var1=val1 117 | var2=val2 118 | 119 | [section1] 120 | aaa=asdf 121 | bbb=123 122 | ccc=true 123 | 124 | [section2] 125 | ddd=asdfasd 126 | eee=1234 127 | fff=false 128 | ``` 129 | 130 | Look into the `site.yaml` and `templates/*.j2` for more examples. 131 | 132 | 133 | Puppet example 134 | -------------- 135 | 136 | Clone this repo to some directory (e.g. `/etc/puppet/encoder`): 137 | 138 | ``` 139 | $ git clone https://github.com/picotrading/config-encoder-macros /etc/puppet/encoder 140 | ``` 141 | 142 | Then use the macros from your Puppet manifest like this: 143 | 144 | ``` 145 | # Load the configuration from YAML file 146 | $ini_data = hiera('ini_data') 147 | 148 | file { '/tmp/test.ini' : 149 | ensure => present, 150 | content => template('test.ini.erb'), 151 | } 152 | ``` 153 | 154 | Where the Hiera YAML file contains: 155 | 156 | ``` 157 | --- 158 | 159 | ini_data: 160 | var1: val1 161 | var2: val2 162 | section1: 163 | aaa: 164 | - asdf 165 | - zxcv 166 | bbb: 123 167 | ccc: 'true' 168 | section2: 169 | ddd: asdfasd 170 | eee: 1234 171 | fff: 'false' 172 | ``` 173 | 174 | And the `templates/test.ini.erb` contains: 175 | 176 | ``` 177 | # 178 | # This file is managed by Puppet. 179 | # Do not edit this file manually. 180 | # Any changes will be automatically reverted. 181 | # 182 | 183 | <%- 184 | item = @ini_data || (ini_data.kind_of?(String) ? eval(ini_data) : ini_data) 185 | -%> 186 | <%= ERB.new(IO.read('/etc/puppet/macros/ini_encode_macro.erb'), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 187 | ``` 188 | 189 | And if you run Puppet you should get the following in the `/tmp/test.ini`: 190 | 191 | ``` 192 | # 193 | # This file is managed by Puppet. 194 | # Do not edit this file manually. 195 | # Any changes will be automatically reverted. 196 | # 197 | 198 | var1=val1 199 | var2=val2 200 | 201 | [section1] 202 | aaa=asdf 203 | bbb=123 204 | ccc=true 205 | 206 | [section2] 207 | ddd=asdfasd 208 | eee=1234 209 | fff=false 210 | ``` 211 | 212 | Look into the `site.pp`, `templates/*.erb` and `puppet_apply.sh` for more 213 | examples. 214 | 215 | 216 | Macros parameters 217 | ----------------- 218 | 219 | The first parameter passed to the macro is always the data structure. Any 220 | following parameter should be addressed by a keyword (e.g. `indent=" "` where 221 | `indent` is the keyword). 222 | 223 | 224 | ### `apache_encode()` 225 | 226 | - `item` 227 | 228 | > Variable holding the input data for the macro. 229 | 230 | - `convert_bools=false` 231 | 232 | > Indicates whether Boolean values presented as a string should be converted 233 | > to a real Booblean value. For example `var1: 'True'` would be represented 234 | > as a string but using the `convert_bools=true` will convert it to a Boolean 235 | > like it would be defined like this: `var1: true`. 236 | 237 | - `convert_nums=false` 238 | 239 | > Indicates whether number presented as a string should be converted to 240 | > number. For example `var1: '123'` would be represented as a string but 241 | > using the `convert_nums=true` will convert it to a number like it would 242 | > be defined like this: `var1: 123`. You can also use the YAML type casting 243 | > to convert string to number (e.g. `!!int "1234"`, `!!float "3.14"`). 244 | 245 | - `indent=" "` 246 | 247 | > Defines the indentation unit. 248 | 249 | - `type="section"` 250 | 251 | > Defines the type of the `item` in the recursive macro calls. It's used only 252 | > internally in the macro. 253 | 254 | - `level=0` 255 | 256 | > Indicates the initial level of the indentation. Value `0` starts indenting 257 | > from the beginning of the line. Setting the value to higher than `0` 258 | > indents the content by `indent * level`. 259 | 260 | - `macro_path='macros/apache_encode_macro.erb'` 261 | 262 | > Relative or absolute path to the macro. It's used only in ERB macros. 263 | 264 | 265 | ### `erlang_encode()` 266 | 267 | - `item` 268 | 269 | > Variable holding the input data for the macro. 270 | 271 | - `convert_bools=false` 272 | 273 | > Indicates whether Boolean values presented as a string should be converted 274 | > to a real Booblean value. For example `var1: 'True'` would be represented 275 | > as a string but using the `convert_bools=true` will convert it to a Boolean 276 | > like it would be defined like this: `var1: true`. 277 | 278 | - `convert_nums=false` 279 | 280 | > Indicates whether number presented as a string should be converted to 281 | > number. For example `var1: '123'` would be represented as a string but 282 | > using the `convert_nums=true` will convert it to a number like it would 283 | > be defined like this: `var1: 123`. You can also use the YAML type casting 284 | > to convert string to number (e.g. `!!int "1234"`, `!!float "3.14"`). 285 | 286 | - `first=[]` 287 | 288 | > Indicates whether the item being processed is actually a first item. It's 289 | > used only internally in the macro. 290 | 291 | - `indent=" "` 292 | 293 | > Defines the indentation unit. 294 | 295 | - `level=0` 296 | 297 | > Indicates the initial level of the indentation. Value `0` starts indenting 298 | > from the beginning of the line. Setting the value to higher than `0` 299 | > indents the content by `indent * level`. 300 | 301 | - `macro_path='macros/erlang_encode_macro.erb'` 302 | 303 | > Relative or absolute path to the macro. It's used only in ERB macros. 304 | 305 | 306 | ### `ini_encode()` 307 | - `item` 308 | 309 | > Variable holding the input data for the macro. 310 | 311 | - `delimiter="="` 312 | 313 | > Sign separating the *property* and the *value*. By default it's set to `'='` 314 | > but it can also be set to `' = '`. 315 | 316 | - `first=[]` 317 | 318 | > Indicates whether the item being processed is actually a first item. It's 319 | > used only internally in the macro. 320 | 321 | - `macro_path='macros/ini_encode_macro.erb'` 322 | 323 | > Relative or absolute path to the macro. It's used only in ERB macros. 324 | 325 | - `quote=""` 326 | 327 | > Allows to set the *value* quoting. Use `quote="'"` or `quote='"'`. 328 | 329 | - `section_is_comment=false` 330 | 331 | > Prints sections as comments. 332 | 333 | - `ucase_prop=false` 334 | 335 | > Indicates whether the *property* should be made uppercase. 336 | 337 | 338 | ### `json_encode()` 339 | - `item` 340 | 341 | > Variable holding the input data for the macro. 342 | 343 | - `convert_bools=false` 344 | 345 | > Indicates whether Boolean values presented as a string should be converted 346 | > to a real Booblean value. For example `var1: 'True'` would be represented 347 | > as a string but using the `convert_bools=true` will convert it to a Boolean 348 | > like it would be defined like this: `var1: true`. 349 | 350 | - `convert_nums=false` 351 | 352 | > Indicates whether number presented as a string should be converted to 353 | > number. For example `var1: '123'` would be represented as a string but 354 | > using the `convert_nums=true` will convert it to a number like it would 355 | > be defined like this: `var1: 123`. You can also use the YAML type casting 356 | > to convert string to number (e.g. `!!int "1234"`, `!!float "3.14"`). 357 | 358 | - `indent=" "` 359 | 360 | > Defines the indentation unit. 361 | 362 | - `level=0` 363 | 364 | > Indicates the initial level of the indentation. Value `0` starts indenting 365 | > from the beginning of the line. Setting the value to higher than `0` 366 | > indents the content by `indent * level`. 367 | 368 | - `macro_path='macros/json_encode_macro.erb'` 369 | 370 | > Relative or absolute path to the macro. It's used only in ERB macros. 371 | 372 | 373 | ### `logstash_encode()` 374 | 375 | - `item` 376 | 377 | > Variable holding the input data for the macro. 378 | 379 | - `convert_bools=false` 380 | 381 | > Indicates whether Boolean values presented as a string should be converted 382 | > to a real Booblean value. For example `var1: 'True'` would be represented 383 | > as a string but using the `convert_bools=true` will convert it to a Boolean 384 | > like it would be defined like this: `var1: true`. You can also use the YAML 385 | > type casting by using `!!bool` in front of your value (e.g. 386 | > `!!bool "true"`). 387 | 388 | - `convert_nums=false` 389 | 390 | > Indicates whether number presented as a string should be converted to 391 | > number. For example `var1: '123'` would be represented as a string but 392 | > using the `convert_nums=true` will convert it to a number like it would 393 | > be defined like this: `var1: 123`. You can also use the YAML type casting 394 | > to convert string to number (e.g. `!!int "1234"`, `!!float "3.14"`). 395 | 396 | - `indent=" "` 397 | 398 | > Defines the indentation unit. 399 | 400 | - `level=0` 401 | 402 | > Indicates the initial level of the indentation. Value `0` starts indenting 403 | > from the beginning of the line. Setting the value to higher than `0` 404 | > indents the content by `indent * level`. 405 | 406 | - `prevtype=""` 407 | 408 | > Defines the type of the previous item in the recursive macro calls. It's used 409 | > only internally in the macro. 410 | 411 | 412 | ### `toml_encode()` 413 | 414 | - `item` 415 | 416 | > Variable holding the input data for the macro. 417 | 418 | - `convert_bools=false` 419 | 420 | > Indicates whether Boolean values presented as a string should be converted 421 | > to a real Booblean value. For example `var1: 'True'` would be represented 422 | > as a string but using the `convert_bools=true` will convert it to a Boolean 423 | > like it would be defined like this: `var1: true`. You can also use the YAML 424 | > type casting by using `!!bool` in front of your value (e.g. 425 | > `!!bool "true"`). 426 | 427 | - `convert_nums=false` 428 | 429 | > Indicates whether number presented as a string should be converted to 430 | > number. For example `var1: '123'` would be represented as a string but 431 | > using the `convert_nums=true` will convert it to a number like it would 432 | > be defined like this: `var1: 123`. You can also use the YAML type casting 433 | > to convert string to number (e.g. `!!int "1234"`, `!!float "3.14"`). 434 | 435 | - `first=[]` 436 | 437 | > Indicates whether the item being processed is actually a first item. It's 438 | > used only internally in the macro. 439 | 440 | - `indent=" "` 441 | 442 | > Defines the indentation unit. 443 | 444 | - `level=0` 445 | 446 | > Indicates the initial level of the indentation. Value `0` starts indenting 447 | > from the beginning of the line. Setting the value to higher than `0` 448 | > indents the content by `indent * level`. 449 | 450 | - `macro_path='macros/toml_encode_macro.erb'` 451 | 452 | > Relative or absolute path to the macro. It's used only in ERB macros. 453 | 454 | - `prevkey=""` 455 | 456 | > Defines the name of the previous key in the recursive macro calls. It's used 457 | > only internally in the macro. 458 | 459 | - `prevtype=""` 460 | 461 | > Defines the type of the previous item in the recursive macro calls. It's used 462 | > only internally in the macro. 463 | 464 | - `quote='"'` 465 | 466 | > Allows to set the *value* quoting. Use `quote="'"` or `quote='"'`. 467 | 468 | 469 | ### `xml_encode()` 470 | - `item` 471 | 472 | > Variable holding the input data for the macro. 473 | 474 | - `first=[]` 475 | 476 | > Indicates whether the item being processed is actually a first item. It's 477 | > used only internally in the macro. 478 | 479 | - `indent=" "` 480 | 481 | > Defines the indentation unit. 482 | 483 | - `level=0` 484 | 485 | > Indicates the initial level of the indentation. Value `0` starts indenting 486 | > from the beginning of the line. Setting the value to higher than `0` 487 | > indents the content by `indent * level`. 488 | 489 | - `macro_path='macros/xml_encode_macro.erb'` 490 | 491 | > Relative or absolute path to the macro. It's used only in ERB macros. 492 | 493 | - `prevkey=none` 494 | 495 | > Defines the name of the previous key in the recursive macro calls. It's used 496 | > only internally in the macro. 497 | 498 | 499 | ### `yaml_encode()` 500 | - `item` 501 | 502 | > Variable holding the input data for the macro. 503 | 504 | - `convert_bools=false` 505 | 506 | > Indicates whether Boolean values presented as a string should be converted 507 | > to a real Booblean value. For example `var1: 'True'` would be represented 508 | > as a string but using the `convert_bools=true` will convert it to a Boolean 509 | > like it would be defined like this: `var1: true`. 510 | 511 | - `convert_nums=false` 512 | 513 | > Indicates whether number presented as a string should be converted to 514 | > number. For example `var1: '123'` would be represented as a string but 515 | > using the `convert_nums=true` will convert it to a number like it would 516 | > be defined like this: `var1: 123`. You can also use the YAML type casting 517 | > to convert string to number (e.g. `!!int "1234"`, `!!float "3.14"`). 518 | 519 | - `indent=" "` 520 | 521 | > Defines the indentation unit. 522 | 523 | - `level=0` 524 | 525 | > Indicates the initial level of the indentation. Value `0` starts indenting 526 | > from the beginning of the line. Setting the value to higher than `0` 527 | > indents the content by `indent * level`. 528 | 529 | - `macro_path='macros/yaml_encode_macro.erb'` 530 | 531 | > Relative or absolute path to the macro. It's used only in ERB macros. 532 | 533 | - `quote='"'` 534 | 535 | > Allows to set the *value* quoting. Use `quote="'"` or `quote='"'`. 536 | 537 | - `skip_indent=false` 538 | 539 | > Indicates whether the indentation should be skipped for the specific item. 540 | > It's used only internally in the macro. 541 | 542 | 543 | Limitations 544 | ----------- 545 | 546 | ### Erlang, JSON, TOML and YAML macros 547 | 548 | In these type-sensitive file formats, the Boolean values represented as string 549 | (`"true"`, `"True"`, `"false"` and `"False"`) are automatically converted to 550 | Boolean value (`true` and `false`). The reason for this behavior is that if you 551 | want to pass a Boolean variable in Ansible, you have to actually quote it (e.g. 552 | `var1: "{{ my_boolean_var }}"`). Once the variable is quoted, it's not Boolean 553 | any more. If you want to use Boolean as a string in your final configuration 554 | file, try to use the value with a space (e.g. `' true'`). 555 | 556 | 557 | ### INI macro 558 | 559 | This macro doesn't respect the order in which the data was defined. It probably 560 | need to be fixed as some config files might allow to overwrite previous 561 | definitions. 562 | 563 | 564 | ### XML macro 565 | 566 | YAML doesn't allow to fully map XML data with attributes. This is why XML 567 | attributes must be defined as part of the element name (e.g. `'elem attr1="val1" 568 | attr2="val2"': Value of the element`). This is also the reason why elements of 569 | the same name can only have the same set of attributes. For example the following YAML 570 | input data: 571 | 572 | ``` 573 | --- 574 | root: 575 | 'elem attr1="val1" attr2="val2"': 576 | - element value1 577 | - element value2 578 | ``` 579 | 580 | Will produce the following XML file (`elem` has the same set of attributes): 581 | 582 | ``` 583 | 584 | element value1 585 | element value2 586 | 587 | ``` 588 | 589 | Another limitation of the XML macro is that attributes can not have value 590 | derivated from a Jinja2 variable in the Ansible context. This macro also doesn't 591 | allow to set order of the elements so it's suitable only for order-insensitive 592 | XML files. 593 | 594 | 595 | Python example 596 | -------------- 597 | 598 | Although the macros are intended to be used primarily in Ansible, they can also 599 | be used directly from Python: 600 | 601 | ``` 602 | from jinja2 import Template 603 | from yaml import load 604 | import sys 605 | 606 | # Load the YAML data to Python data structure 607 | yaml_fh = open('vars/ini_test.yaml') 608 | yaml_struct = load(yaml_fh) 609 | yaml_fh.close() 610 | 611 | # Take only the content of the ini_data variable 612 | yaml_struct = yaml_struct['ini_data'] 613 | 614 | # Read Jinja2 template as text 615 | template_fh = open('macros/ini_encode_macro.j2') 616 | template_text = template_fh.read() 617 | template_fh.close() 618 | 619 | # Create Jinja2 template object 620 | t = Template(template_text) 621 | # Convert the YAML data to INI format 622 | output = t.module.ini_encode(yaml_struct).encode('utf8') 623 | 624 | # Print the result 625 | sys.stdout.write(output) 626 | ``` 627 | 628 | Or you can use the `yaml_converter.py`: 629 | 630 | ``` 631 | $ ./yaml_converter.py -f ini -v ini_data -y ./vars/ini_test.yaml 632 | ``` 633 | 634 | 635 | Ruby example 636 | ------------ 637 | 638 | ``` 639 | require 'erb' 640 | require 'ostruct' 641 | require 'yaml' 642 | 643 | # Helper variables 644 | yaml_file = './vars/ini_test.yaml' 645 | var = 'ini_data' 646 | 647 | # Define variables used in the macro 648 | item = YAML.load_file(yaml_file)[var] 649 | macro_path = './macros/ini_encode_macro.erb' 650 | 651 | # Convert the YAML data to the final format 652 | binding = OpenStruct.new.send(:binding) 653 | print ERB.new(IO.read(macro_path), nil, '-', '_erbout0').result(binding) 654 | ``` 655 | 656 | Or you can use the `yaml_converter.rb`: 657 | 658 | ``` 659 | $ ./yaml_converter.rb -f ini -v ini_data -y ./vars/ini_test.yaml 660 | ``` 661 | 662 | 663 | License 664 | ------- 665 | 666 | MIT 667 | 668 | 669 | Author 670 | ------ 671 | 672 | Jiri Tyr 673 | -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | :backends: 2 | - yaml 3 | :hierarchy: 4 | - apache_test 5 | - erlang_test 6 | - ini_test 7 | - json_test 8 | - toml_test 9 | - xml_test 10 | - yaml_test 11 | :yaml: 12 | :datadir: ./vars 13 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | localhost ansible_python_interpreter=/usr/bin/python2 ansible_connection=local 2 | -------------------------------------------------------------------------------- /macros/apache_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to Apache format 3 | #-%> 4 | <%- 5 | _item ||= Array.new 6 | _type ||= Array.new 7 | _is_empty ||= Array.new 8 | convert_bools ||= false 9 | convert_nums ||= false 10 | indent ||= ' ' 11 | level ||= 0 12 | macro_path ||= 'macros/apache_encode_macro.erb' 13 | quote_all_nums ||= false 14 | quote_all_strings ||= false 15 | type ||= 'sections' 16 | -%> 17 | <%- if type == 'sections' -%> 18 | <%- item['content'].each do |c| -%> 19 | <%-# First check if this section has options -%> 20 | <%- if c.include?('options') -%> 21 | <%- 22 | _item.push(item) 23 | _type.push(type) 24 | item = c['options'] 25 | type = 'options' 26 | level = level+1 27 | -%> 28 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 29 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 30 | <%- 31 | item = _item.pop() 32 | type = _type.pop() 33 | level = level-1 34 | -%> 35 | <%- end -%> 36 | <%- is_empty = [] -%> 37 | <%-# Check if this section has some sub-sections -%> 38 | <%- if c.include?('sections') -%> 39 | <%- c['sections'].each do |s| -%> 40 | <%-# Check for empty sub-sections -%> 41 | <%- s['content'].each do |i| -%> 42 | <%- if (i.include?('options') and i['options'].length > 0) or 43 | (i.include?('sections') and i['sections'].length > 0) -%> 44 | <%- is_empty.push(1) -%> 45 | <%- end -%> 46 | <%- end -%> 47 | <%- if is_empty.length > 0 -%> 48 | <%--%><%= indent * level + '<' + s['name'] -%> 49 | <%- if s.include?('param') -%> 50 | <%--%><%= ' ' -%> 51 | <%- 52 | _item.push(item) 53 | _type.push(type) 54 | item = s['param'] 55 | type = 'value' 56 | level = level+1 57 | -%> 58 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 59 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 60 | <%- 61 | item = _item.pop() 62 | type = _type.pop() 63 | level = level-1 64 | -%> 65 | <%- end -%> 66 | <%--%><%= ">\n" -%> 67 | <%- 68 | _item.push(item) 69 | _type.push(type) 70 | item = s 71 | type = 'sections' 72 | level = level+1 73 | -%> 74 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 75 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 76 | <%- 77 | item = _item.pop() 78 | type = _type.pop() 79 | level = level-1 80 | -%> 81 | <%--%><%= indent * level + '\n" -%> 82 | <%- if c != item['content'].last -%> 83 | <%--%><%= "\n" -%> 84 | <%- end -%> 85 | <%- end -%> 86 | <%- end -%> 87 | <%- end -%> 88 | <%- if c != item['content'].last and 89 | ( 90 | c.include?('options') and c['options'].length > 0 or 91 | ( 92 | c.include?('sections') and c['sections'].length > 0 and 93 | is_empty.length > 0 94 | ) 95 | ) 96 | -%> 97 | <%--%><%= "\n" -%> 98 | <%- end -%> 99 | <%- end -%> 100 | <%- elsif type == 'options' -%> 101 | <%- item.each do |o| -%> 102 | <%- o.sort.each do |key, val| -%> 103 | <%--%><%= indent * (level-1) + key + ' ' -%> 104 | <%- 105 | _item.push(item) 106 | _type.push(type) 107 | item = val 108 | type = 'value' 109 | level = level+1 110 | -%> 111 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 112 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 113 | <%- 114 | item = _item.pop() 115 | type = _type.pop() 116 | level = level-1 117 | -%> 118 | <%--%><%= "\n" -%> 119 | <%- end -%> 120 | <%- end -%> 121 | <%- elsif type == 'value' -%> 122 | <%- if item.kind_of?(TrueClass) or item.kind_of?(FalseClass) or 123 | convert_bools and ['true', 'True', 'false', 'False'].include?(item) -%> 124 | <%-# Value is a boolean -%> 125 | <%--%><%= item.to_s.downcase -%> 126 | <%- elsif item.kind_of?(Numeric) or 127 | (convert_nums and ( 128 | item.to_i.to_s == item or 129 | item.to_f.to_s == item)) or 130 | (convert_bools and ['true', 'True', 'false', 'False'].include?(item)) or 131 | item.kind_of?(TrueClass) or item.kind_of?(FalseClass) -%> 132 | <%-# Value is a number -%> 133 | <%- if quote_all_nums -%> 134 | <%--%><%= '"' + item.to_s + '"' -%> 135 | <%- else -%> 136 | <%--%><%= item -%> 137 | <%- end -%> 138 | <%- elsif item.kind_of?(String) -%> 139 | <%-# Value is a string -%> 140 | <%- if quote_all_strings or 141 | item.include?(' ') or 142 | item.include?("\t") or 143 | item.include?("\n") or 144 | item.include?("\r") or 145 | item == '' -%> 146 | <%--%><%= '"' + item.to_s.gsub('\\', '\\\\').gsub('"', '\\"') + '"' -%> 147 | <%- else -%> 148 | <%--%><%= item -%> 149 | <%- end -%> 150 | <%- elsif ! item.kind_of?(Hash) -%> 151 | <%-# Value is an array -%> 152 | <%- item.each do |v| -%> 153 | <%- 154 | _item.push(item) 155 | _type.push(type) 156 | item = v 157 | type = 'value' 158 | level = level+1 159 | -%> 160 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 161 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 162 | <%- 163 | item = _item.pop() 164 | type = _type.pop() 165 | level = level-1 166 | -%> 167 | <%- if v != item.last -%> 168 | <%--%><%= ' ' -%> 169 | <%- end -%> 170 | <%- end -%> 171 | <%- end -%> 172 | <%- end -%> 173 | -------------------------------------------------------------------------------- /macros/apache_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to Apache format 3 | #} 4 | 5 | {%- macro apache_encode( 6 | item, 7 | convert_bools=false, 8 | convert_nums=false, 9 | indent=" ", 10 | level=0, 11 | quote_all_nums=false, 12 | quote_all_strings=false, 13 | type="sections") %} 14 | 15 | {%- if type == "sections" %} 16 | {%- for c in item["content"] %} 17 | {#- First check if this section has options #} 18 | {%- if "options" in c -%} 19 | {{ apache_encode( 20 | c["options"], 21 | convert_bools=convert_bools, 22 | convert_nums=convert_nums, 23 | indent=indent, 24 | level=level+1, 25 | quote_all_nums=quote_all_nums, 26 | quote_all_strings=quote_all_strings, 27 | type="options") }} 28 | {%- endif %} 29 | 30 | {%- set is_empty = [] %} 31 | 32 | {#- Check if this section has some sub-sections #} 33 | {%- if "sections" in c %} 34 | {%- for s in c["sections"] %} 35 | 36 | {#- Check for empty sub-sections #} 37 | {%- for i in s["content"] %} 38 | {%- if ('options' in i and i['options'] | length > 0) or 39 | ('sections' in i and i['sections'] | length > 0) %} 40 | {%- if is_empty.append(1) %}{% endif %} 41 | {%- endif %} 42 | {%- endfor %} 43 | 44 | {%- if is_empty | length > 0 -%} 45 | {{ indent * level ~ "<" ~ s["name"] ~ (" " ~ 46 | apache_encode( 47 | s["param"], 48 | convert_bools=convert_bools, 49 | convert_nums=convert_nums, 50 | indent=indent, 51 | level=level+1, 52 | quote_all_nums=quote_all_nums, 53 | quote_all_strings=quote_all_strings, 54 | type="value") 55 | if "param" in s else "") ~ ">\n" ~ 56 | apache_encode( 57 | s, 58 | convert_bools=convert_bools, 59 | convert_nums=convert_nums, 60 | indent=indent, 61 | level=level+1, 62 | quote_all_nums=quote_all_nums, 63 | quote_all_strings=quote_all_strings, 64 | type="sections") ~ 65 | indent * level ~ "\n" }} 66 | 67 | {%- if not loop.last -%} 68 | {{ "\n" }} 69 | {%- endif %} 70 | {%- endif %} 71 | {%- endfor %} 72 | {%- endif %} 73 | 74 | {%- if not loop.last and 75 | ( 76 | "options" in c and c["options"] | length > 0 or 77 | ( 78 | "sections" in c and c["sections"] | length > 0 and 79 | is_empty | length > 0 80 | ) 81 | ) 82 | -%} 83 | {{ "\n" }} 84 | {%- endif %} 85 | {%- endfor %} 86 | 87 | {%- elif type == "options" %} 88 | {%- for o in item -%} 89 | {%- for key, val in o.iteritems() | sort -%} 90 | {{ indent * (level-1) ~ key ~ " " ~ 91 | apache_encode( 92 | val, 93 | convert_bools=convert_bools, 94 | convert_nums=convert_nums, 95 | indent=indent, 96 | level=level+1, 97 | quote_all_nums=quote_all_nums, 98 | quote_all_strings=quote_all_strings, 99 | type="value") ~ "\n" }} 100 | {%- endfor %} 101 | {%- endfor %} 102 | 103 | {%- elif type == "value" %} 104 | {%- if item in [True, False] or 105 | convert_bools and (item in ["true", "True", "false", "False"]) %} 106 | {#- Value is a boolean -#} 107 | {{ item | lower }} 108 | 109 | {%- elif item is number or 110 | (convert_nums and ( 111 | item | int | string == item or 112 | item | float | string == item)) or 113 | (convert_bools and item in ["true", "True", "false", "False"]) or 114 | item in [True, False] %} 115 | {#- Value is a number -#} 116 | {%- if quote_all_nums -%} 117 | "{{ item }}" 118 | {%- else -%} 119 | {{ item }} 120 | {%- endif %} 121 | 122 | {%- elif item is string %} 123 | {#- Value is a string #} 124 | {%- if quote_all_strings or 125 | " " in item or 126 | "\t" in item or 127 | "\n" in item or 128 | "\r" in item or 129 | item == "" -%} 130 | 131 | "{{ item | replace("\\", "\\\\") | replace('"', '\\"') }}" 132 | {%- else -%} 133 | {{ item }} 134 | {%- endif %} 135 | 136 | {%- elif item is not mapping %} 137 | {#- Value is a list #} 138 | {%- for v in item -%} 139 | {{ apache_encode( 140 | v, 141 | convert_bools=convert_bools, 142 | convert_nums=convert_nums, 143 | indent=indent, 144 | level=level+1, 145 | quote_all_nums=quote_all_nums, 146 | quote_all_strings=quote_all_strings, 147 | type="value") }} 148 | 149 | {%- if not loop.last -%} 150 | {{ " " }} 151 | {%- endif %} 152 | {%- endfor %} 153 | {%- endif %} 154 | 155 | {%- endif %} 156 | 157 | {%- endmacro %} 158 | -------------------------------------------------------------------------------- /macros/erlang_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to Erlang config format 3 | #-%> 4 | <%- 5 | _item ||= Array.new 6 | convert_bools ||= false 7 | convert_nums ||= false 8 | first ||= Array.new 9 | indent ||= ' ' 10 | level ||= 0 11 | macro_path ||= 'macros/erlang_encode_macro.erb' 12 | -%> 13 | <%- if item.kind_of?(Hash) -%> 14 | <%-# The item is a hash #-%> 15 | <%--%><%= "\n" -%> 16 | <%- first.push(1) -%> 17 | <%- item.sort.each do |key, val| -%> 18 | <%--%><%= indent * level + '{' + key.to_s + ',' -%> 19 | <%- if ! val.kind_of?(Hash) -%> 20 | <%--%><%= ' ' -%> 21 | <%- end -%> 22 | <%- 23 | _item.push(item) 24 | 25 | item = val 26 | level = level+1 27 | -%> 28 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 29 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 30 | <%- 31 | level = level-1 32 | item = _item.pop() 33 | -%> 34 | <%--%><%= '}' -%> 35 | <%- if key != item.keys.sort.last -%> 36 | <%--%><%= ",\n" -%> 37 | <%- end -%> 38 | <%- end -%> 39 | <%- elsif item.nil? or item.kind_of?(Numeric) or 40 | (convert_nums && ( 41 | item.to_i.to_s == item or 42 | item.to_f.to_s == item)) or 43 | (convert_bools && ['true', 'True', 'false', 'False'].include?(item)) or 44 | item.kind_of?(TrueClass) or item.kind_of?(FalseClass) -%> 45 | <%-# Item is a value of a number, null or boolean #-%> 46 | <%--%><%= item.to_s.downcase -%> 47 | <%- elsif item.kind_of?(String) -%> 48 | <%-# The item is a string #-%> 49 | <%--%><%= '"' + item.to_s + '"' -%> 50 | <%- else -%> 51 | <%-# The item is an array #-%> 52 | <%--%><%= '[' -%> 53 | <%- item.each do |val| -%> 54 | <%- if val.kind_of?(String) or val.kind_of?(Numeric) -%> 55 | <%--%><%= "\n" + indent * (level) -%> 56 | <%- end -%> 57 | <%- 58 | _item.push(item) 59 | item = val 60 | level = level+1 61 | -%> 62 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 63 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 64 | <%- 65 | level = level-1 66 | item = _item.pop() 67 | -%> 68 | <%- if val == item.last -%> 69 | <%--%><%= "\n" -%> 70 | <%- else -%> 71 | <%--%><%= ',' -%> 72 | <%- end -%> 73 | <%- end -%> 74 | <%- if item.length > 0 -%> 75 | <%--%><%= indent * (level-1 > 0 ? level-1 : 0) + ']' -%> 76 | <%- else -%> 77 | <%--%><%= ']' -%> 78 | <%- end -%> 79 | <%- if level == 0 -%> 80 | <%--%><%= ".\n" -%> 81 | <%- end -%> 82 | <%- end -%> 83 | -------------------------------------------------------------------------------- /macros/erlang_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to Erlang config format 3 | #} 4 | 5 | {%- macro erlang_encode( 6 | item, 7 | convert_bools=false, 8 | convert_nums=false, 9 | first=[], 10 | indent=" ", 11 | level=0) %} 12 | 13 | {%- if item is mapping %} 14 | {#- The item is a dict -#} 15 | 16 | {{ "\n" }} 17 | 18 | {%- if first.append(1) %}{% endif %} 19 | 20 | {%- for key, val in item.iteritems() | sort -%} 21 | {{ indent * level ~ "{" ~ key ~ "," }} 22 | 23 | {%- if val is not mapping -%} 24 | {{ " " }} 25 | {%- endif -%} 26 | 27 | {{ erlang_encode( 28 | val, 29 | convert_bools=convert_bools, 30 | convert_nums=convert_nums, 31 | first=first, 32 | indent=indent, 33 | level=level+1) }}{{ "}" }} 34 | 35 | {%- if not loop.last -%} 36 | {{ ",\n" }} 37 | {%- endif -%} 38 | {%- endfor %} 39 | 40 | {%- elif item == "null" or item is number or 41 | (convert_nums and ( 42 | item | int | string == item or 43 | item | float | string == item)) or 44 | (convert_bools and item in ["true", "True", "false", "False"]) or 45 | item in [True, False] %} 46 | 47 | {#- Item is a value of a number, null or boolean -#} 48 | 49 | {{ item | lower }} 50 | 51 | {%- elif item is string %} 52 | {#- The item is a string -#} 53 | 54 | {{ '"' ~ item ~ '"' }} 55 | 56 | {%- else %} 57 | {#- The item is a list -#} 58 | 59 | {{ "[" }} 60 | 61 | {%- for val in item -%} 62 | {%- if val is string or val is number -%} 63 | {{ "\n" ~ indent * (level) }} 64 | {%- endif -%} 65 | 66 | {{ erlang_encode( 67 | val, 68 | convert_bools=convert_bools, 69 | convert_nums=convert_nums, 70 | first=first, 71 | indent=indent, 72 | level=level+1) }} 73 | 74 | {%- if loop.last -%} 75 | {{ "\n" }} 76 | {%- else -%} 77 | {{ "," }} 78 | {%- endif %} 79 | {%- endfor -%} 80 | 81 | {%- if item | length > 0 -%} 82 | {{ indent * (level-1) ~ "]" }} 83 | {%- else -%} 84 | {{ "]" }} 85 | {%- endif %} 86 | 87 | {%- if level == 0 -%} 88 | {{ ".\n" }} 89 | {%- endif %} 90 | 91 | {%- endif %} 92 | {%- endmacro %} 93 | -------------------------------------------------------------------------------- /macros/ini_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%# 2 | # ERB macro which converts Ruby data structure to INI format 3 | #-%> 4 | <%- 5 | item ||= {} 6 | delimiter ||= '=' 7 | first ||= Array.new 8 | quote ||= '' 9 | section_is_comment ||= false 10 | ucase_prop ||= false -%> 11 | <%-# First process vars without a section -%> 12 | <%- item.sort.each do |property, value| -%> 13 | <%- if ! value.kind_of?(Hash) -%> 14 | <%- if first.length == 0 -%> 15 | <%- first.push(1) -%> 16 | <%- end -%> 17 | <%- if value.kind_of?(String) or value.kind_of?(Numeric) -%> 18 | <%--%><%= (ucase_prop ? property.to_s.upcase : property) + delimiter + 19 | quote + value.to_s + quote + "\n" -%> 20 | <%- else -%> 21 | <%- value.each do |i| -%> 22 | <%--%><%= (ucase_prop ? property.to_s.upcase : property) + delimiter + 23 | quote + i.to_s + quote + "\n" -%> 24 | <%- end -%> 25 | <%- end -%> 26 | <%- end -%> 27 | <%- end -%> 28 | <%#- Then process vars with a section -%> 29 | <%- item.sort.each do |section, options| -%> 30 | <%- if options.kind_of?(Hash) -%> 31 | <%- if first.length == 0 -%> 32 | <%- first.push(1) -%> 33 | <%- else -%> 34 | <%--%><%= "\n" -%> 35 | <%- end -%> 36 | <%- if section_is_comment -%> 37 | <%--%><%= '# ' + section.to_s + "\n" -%> 38 | <%- else -%> 39 | <%--%><%= '[' + section.to_s + "]\n" -%> 40 | <%- end -%> 41 | <%- options.sort.each do |property, value| -%> 42 | <%- if value.kind_of?(String) or value.kind_of?(Numeric) -%> 43 | <%--%><%= (ucase_prop ? property.to_s.upcase : property) + delimiter + 44 | quote + value.to_s + quote + "\n" -%> 45 | <%- else -%> 46 | <%- value.each do |v| -%> 47 | <%--%><%= (ucase_prop ? property.to_s.upcase : property) + 48 | delimiter + quote + v.to_s + quote + "\n" -%> 49 | <%- end -%> 50 | <%- end -%> 51 | <%- end -%> 52 | <%- end -%> 53 | <%- end -%> 54 | -------------------------------------------------------------------------------- /macros/ini_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to INI format 3 | #} 4 | 5 | {%- macro ini_encode( 6 | item, 7 | delimiter="=", 8 | first=[], 9 | quote="", 10 | section_is_comment=false, 11 | ucase_prop=false) %} 12 | 13 | {#- First process vars without a section #} 14 | {%- for property, value in item.iteritems() | sort %} 15 | {%- if value is not mapping %} 16 | {%- if first | length == 0 -%} 17 | {%- if first.append(1) %}{% endif %} 18 | {%- endif -%} 19 | 20 | {%- if value is string or value is number -%} 21 | {{ (property | upper if ucase_prop else property) ~ 22 | delimiter ~ quote ~ value ~ quote ~ "\n" }} 23 | {%- else %} 24 | {%- for item in value -%} 25 | {{ (property | upper if ucase_prop else property) ~ 26 | delimiter ~ quote ~ item ~ quote ~ "\n" }} 27 | {%- endfor %} 28 | {%- endif %} 29 | {%- endif %} 30 | {%- endfor %} 31 | 32 | {#- Then process vars with a section #} 33 | {%- for section, options in item.iteritems() | sort %} 34 | {%- if options is mapping -%} 35 | {%- if first | length == 0 -%} 36 | {%- if first.append(1) %}{% endif %} 37 | {%- else -%} 38 | {{ "\n" }} 39 | {%- endif %} 40 | {%- if section_is_comment -%} 41 | {{ "# " ~ section ~ "\n" }} 42 | {%- else -%} 43 | {{ "[" ~ section ~ "]\n" }} 44 | {%- endif %} 45 | {%- for property, value in options.iteritems() | sort -%} 46 | {%- if value is string or value is number -%} 47 | {{ (property | upper if ucase_prop else property) ~ 48 | delimiter ~ quote ~ value ~ quote ~ "\n" }} 49 | {%- else %} 50 | {%- for v in value -%} 51 | {{ (property | upper if ucase_prop else property) ~ 52 | delimiter ~ quote ~ v ~ quote ~ "\n" }} 53 | {%- endfor %} 54 | {%- endif %} 55 | {%- endfor %} 56 | {%- endif %} 57 | {%- endfor %} 58 | {%- endmacro %} 59 | -------------------------------------------------------------------------------- /macros/json_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to JSON format 3 | #-%> 4 | <%- 5 | _item ||= Array.new 6 | convert_bools ||= false 7 | convert_nums ||= false 8 | indent ||= ' ' 9 | level ||= 0 10 | macro_path ||= 'macros/json_encode_macro.erb' 11 | -%> 12 | <%- if item.kind_of?(Hash) -%> 13 | <%-# The item is a hash -%> 14 | <%--%><%= '{' -%> 15 | <%- if item.length > 0 -%> 16 | <%--%><%= "\n" -%> 17 | <%- end -%> 18 | <%- item.sort.each do |key, val| -%> 19 | <%--%><%= indent * (level+1) + '"' + key.to_s + '": ' -%> 20 | <%- 21 | _item.push(item) 22 | 23 | item = val 24 | level = level+1 25 | -%> 26 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 27 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 28 | <%- 29 | level = level-1 30 | item = _item.pop() 31 | -%> 32 | <%- if key == item.keys.sort.last -%> 33 | <%--%><%= "\n" -%> 34 | <%- else -%> 35 | <%--%><%= ",\n" -%> 36 | <%- end -%> 37 | <%- end -%> 38 | <%- if item.length > 0 -%> 39 | <%--%><%= indent * level + '}' -%> 40 | <%- else -%> 41 | <%--%><%= '}' -%> 42 | <%- end -%> 43 | <%- if level == 0 -%> 44 | <%--%><%= "\n" -%> 45 | <%- end -%> 46 | <%- elsif item.kind_of?(Numeric) or 47 | (convert_nums and ( 48 | item.to_i.to_s == item or 49 | item.to_f.to_s == item)) or 50 | (convert_bools and ['true', 'True', 'false', 'False'].include?(item)) or 51 | item.kind_of?(TrueClass) or item.kind_of?(FalseClass) -%> 52 | <%-# Item is a value of a number, null or boolean -%> 53 | <%--%><%= item.to_s -%> 54 | <%- elsif item.kind_of?(String) -%> 55 | <%-# The item is a string -%> 56 | <%--%><%= '"' + item.to_s + '"' -%> 57 | <%- else -%> 58 | <%-# The item is an array -%> 59 | <%--%><%= '[' -%> 60 | <%- if item.length > 0 -%> 61 | <%--%><%= "\n" -%> 62 | <%- end -%> 63 | <%- item.each do |val| -%> 64 | <%--%><%= indent * (level+1) -%> 65 | <%- 66 | _item.push(item) 67 | item = val 68 | level = level+1 69 | -%> 70 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 71 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 72 | <%- 73 | level = level-1 74 | item = _item.pop() 75 | -%> 76 | <%- if val == item.last -%> 77 | <%--%><%= "\n" -%> 78 | <%- else -%> 79 | <%--%><%= ",\n" -%> 80 | <%- end -%> 81 | <%- end -%> 82 | <%- if item.length > 0 -%> 83 | <%--%><%= indent * level + ']' -%> 84 | <%- else -%> 85 | <%--%><%= ']' -%> 86 | <%- end -%> 87 | <%- end -%> 88 | -------------------------------------------------------------------------------- /macros/json_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to JSON format 3 | #} 4 | 5 | {%- macro json_encode( 6 | item, 7 | convert_bools=false, 8 | convert_nums=false, 9 | indent=" ", 10 | level=0) %} 11 | 12 | {%- if item is mapping %} 13 | {#- The item is a dict -#} 14 | 15 | {{ "{" }} 16 | 17 | {%- if item | length > 0 -%} 18 | {{ "\n" }} 19 | {%- endif %} 20 | 21 | {%- for key, val in item.iteritems() | sort -%} 22 | {{ indent * (level+1) ~ '"' ~ key ~ '": ' }}{{ json_encode( 23 | val, 24 | convert_bools=convert_bools, 25 | convert_nums=convert_nums, 26 | indent=indent, 27 | level=level+1) }} 28 | 29 | {%- if loop.last -%} 30 | {{ "\n" }} 31 | {%- else -%} 32 | {{ ",\n" }} 33 | {%- endif %} 34 | {%- endfor -%} 35 | 36 | {%- if item | length > 0 -%} 37 | {{ indent * level ~ "}" }} 38 | {%- else -%} 39 | {{ "}" }} 40 | {%- endif %} 41 | 42 | {%- if level == 0 -%} 43 | {{ "\n" }} 44 | {%- endif %} 45 | 46 | {%- elif item == "null" or item is number or 47 | (convert_nums and ( 48 | item | int | string == item or 49 | item | float | string == item)) or 50 | (convert_bools and item in ["true", "True", "false", "False"]) or 51 | item in [True, False] %} 52 | 53 | {#- Item is a value of a number, null or boolean -#} 54 | 55 | {{ item | lower }} 56 | 57 | {%- elif item is string %} 58 | {#- The item is a string -#} 59 | 60 | {{ '"' ~ item ~ '"' }} 61 | 62 | {%- else %} 63 | {#- The item is a list -#} 64 | 65 | {{ "[" }} 66 | 67 | {%- if item | length > 0 -%} 68 | {{ "\n" }} 69 | {%- endif %} 70 | 71 | {%- for val in item -%} 72 | {{ indent * (level+1) }}{{ json_encode( 73 | val, 74 | convert_bools=convert_bools, 75 | convert_nums=convert_nums, 76 | indent=indent, 77 | level=level+1) }} 78 | 79 | {%- if loop.last -%} 80 | {{ "\n" }} 81 | {%- else -%} 82 | {{ ",\n" }} 83 | {%- endif %} 84 | {%- endfor -%} 85 | 86 | {%- if item | length > 0 -%} 87 | {{ indent * level ~ "]" }} 88 | {%- else -%} 89 | {{ "]" }} 90 | {%- endif %} 91 | 92 | {%- endif %} 93 | {%- endmacro %} 94 | -------------------------------------------------------------------------------- /macros/logstash_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to Logstash format 3 | #-%> 4 | TODO 5 | -------------------------------------------------------------------------------- /macros/logstash_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to Logstash format 3 | #} 4 | 5 | {%- macro logstash_encode( 6 | item, 7 | convert_bools=false, 8 | convert_nums=false, 9 | indent=" ", 10 | level=0, 11 | prevtype="") %} 12 | 13 | {%- if item is mapping %} 14 | {#- The item is a dict -#} 15 | 16 | {%- if prevtype in ["value", "value_hash", "array"] -%} 17 | {{ "{\n" }} 18 | {%- endif -%} 19 | 20 | {%- for key, val in item.iteritems() | sort -%} 21 | {%- if key[0] == ":" -%} 22 | {{ indent * level ~ key[1:] ~ " {\n" }}{{ logstash_encode( 23 | val, 24 | convert_bools=convert_bools, 25 | convert_nums=convert_nums, 26 | indent=indent, 27 | level=level+1, 28 | prevtype="block") }} 29 | 30 | {%- if loop.last -%} 31 | {%- if val is string or 32 | val is number or 33 | val in [True, False] or 34 | (val is mapping and val.keys()[0][0] != ":") -%} 35 | {{ "\n" ~ indent * level ~ "}\n" }} 36 | {%- else -%} 37 | {{ indent * level ~ "}\n" }} 38 | {%- endif %} 39 | {%- endif %} 40 | {%- else -%} 41 | {{ indent * level }} 42 | 43 | {%- if prevtype == "value_hash" -%} 44 | {{ '"' ~ key ~ '" => ' }} 45 | {%- else -%} 46 | {{ key ~ " => " }} 47 | {%- endif -%} 48 | 49 | {{ logstash_encode( 50 | val, 51 | convert_bools=convert_bools, 52 | convert_nums=convert_nums, 53 | indent=indent, 54 | level=level+1, 55 | prevtype=("value_hash" if val is mapping else "value")) }} 56 | {%- endif %} 57 | 58 | {%- if not loop.last and 59 | ( 60 | val is string or 61 | val is number or 62 | item in [True, False]) -%} 63 | {{ "\n" }} 64 | {%- endif %} 65 | {%- endfor %} 66 | 67 | {%- if prevtype in ["value", "value_hash", "array"] -%} 68 | {{ "\n" ~ indent * (level-1) ~ "}" }} 69 | 70 | {%- if prevtype in ["value", "value_array"] -%} 71 | {{ "\n" }} 72 | {%- endif %} 73 | {%- endif %} 74 | 75 | {%- elif item is number or 76 | (convert_nums and ( 77 | item | int | string == item or 78 | item | float | string == item)) or 79 | (convert_bools and item in ["true", "True", "false", "False"]) or 80 | item in [True, False] %} 81 | 82 | {#- Item is a value of a number or boolean -#} 83 | 84 | {{ item | lower }} 85 | 86 | {%- elif item is string %} 87 | {#- The item is a string -#} 88 | 89 | {{ '"' ~ item ~ '"' }} 90 | 91 | {%- else %} 92 | {#- The item is a list -#} 93 | 94 | {%- for val in item %} 95 | {%- if val is mapping and val.keys()[0][0] == ":" -%} 96 | {#- value is a block -#} 97 | 98 | {{ logstash_encode( 99 | val, 100 | convert_bools=convert_bools, 101 | convert_nums=convert_nums, 102 | indent=indent, 103 | level=level, 104 | prevtype="block") }} 105 | {%- else %} 106 | {%- if loop.first -%} 107 | {{ "[\n" }} 108 | {%- endif -%} 109 | 110 | {{ indent * level }}{{ logstash_encode( 111 | val, 112 | convert_bools=convert_bools, 113 | convert_nums=convert_nums, 114 | indent=indent, 115 | level=level+1, 116 | prevtype="array") }} 117 | 118 | {%- if loop.last -%} 119 | {{ "\n" ~ indent * (level-1) ~ "]\n" }} 120 | {%- else -%} 121 | {{ ",\n" }} 122 | {%- endif %} 123 | {%- endif %} 124 | {%- endfor -%} 125 | {%- endif %} 126 | {%- endmacro %} 127 | -------------------------------------------------------------------------------- /macros/toml_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to TOML format 3 | #-%> 4 | <%- 5 | _item ||= Array.new 6 | _prevkey ||= Array.new 7 | _prevtype ||= Array.new 8 | _old_prevkey ||= Array.new 9 | _old_level ||= Array.new 10 | convert_bools ||= false 11 | convert_nums ||= false 12 | first ||= Array.new 13 | indent ||= ' ' 14 | level ||= 0 15 | macro_path ||= 'macros/toml_encode_macro.erb' 16 | quote ||= '"' 17 | prevkey ||= '' 18 | prevtype ||= '' 19 | -%> 20 | <%- if item.kind_of?(Hash) -%> 21 | <%-# The item is a hash -%> 22 | <%-# First process all strings, numbers, booleans and arrays -%> 23 | <%- item.sort.each do |key, val| -%> 24 | <%- if val.kind_of?(String) or 25 | val.kind_of?(Numeric) or 26 | val.kind_of?(TrueClass) or val.kind_of?(FalseClass) or 27 | ( 28 | ! val.kind_of?(Hash) and 29 | val.length > 0 and 30 | ! val[0].kind_of?(Hash)) -%> 31 | <%-# The value is a string, a number, or an array -%> 32 | <%--%><%= indent * level + key.to_s + ' = ' -%> 33 | <%- 34 | _item.push(item) 35 | _prevkey.push(prevkey) 36 | _prevtype.push(prevtype) 37 | item = val 38 | prevtype = '' 39 | -%> 40 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 41 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 42 | <%- 43 | prevkey = _prevkey.pop() 44 | prevtype = _prevtype.pop() 45 | item = _item.pop() 46 | -%> 47 | <%- first.push(1) -%> 48 | <%- end -%> 49 | <%- end -%> 50 | <%-# Then process all data structures -%> 51 | <%- item.sort.each do |key, val| -%> 52 | <%- if ! val.kind_of?(String) and 53 | ! val.kind_of?(Numeric) and 54 | ! val.kind_of?(TrueClass) and ! val.kind_of?(FalseClass) and 55 | (val.kind_of?(Hash) or val[0].kind_of?(Hash)) -%> 56 | <%- 57 | old_prevkey = prevkey 58 | old_level = level 59 | -%> 60 | <%- if val.kind_of?(Hash) -%> 61 | <%-# The value is a hash -%> 62 | <%- if prevkey != '' and prevkey != key -%> 63 | <%- level = level + 1 -%> 64 | <%- end -%> 65 | <%- if prevkey == '' -%> 66 | <%- prevkey = key -%> 67 | <%- else -%> 68 | <%- prevkey = prevkey + '.' + key -%> 69 | <%- end -%> 70 | <%- if first.length > 0 -%> 71 | <%--%><%= "\n" -%> 72 | <%- end -%> 73 | <%--%><%= indent * level + '[' + prevkey + ']' + "\n" -%> 74 | <%- elsif val[0].kind_of?(Hash) -%> 75 | <%-# The value is a table -%> 76 | <%- if prevkey == '' -%> 77 | <%- prevkey = key -%> 78 | <%- else -%> 79 | <%- prevkey = prevkey + '.' + key.to_s -%> 80 | <%- end -%> 81 | <%- level = level + 1 -%> 82 | <%- end -%> 83 | <%- 84 | _item.push(item) 85 | _prevkey.push(prevkey) 86 | _prevtype.push(prevtype) 87 | _old_prevkey.push(old_prevkey) 88 | _old_level.push(old_level) 89 | item = val 90 | prevtype = '' 91 | -%> 92 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 93 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 94 | <%- 95 | prevkey = _prevkey.pop() 96 | prevtype = _prevtype.pop() 97 | old_prevkey = _old_prevkey.pop() 98 | old_level = _old_level.pop() 99 | item = _item.pop() 100 | -%> 101 | <%- if val.kind_of?(Hash) and prevkey != '' and prevkey != key or 102 | val[0].kind_of?(Hash) -%> 103 | <%- level = level - 1 -%> 104 | <%- end -%> 105 | <%- 106 | prevkey = old_prevkey 107 | level = old_level 108 | -%> 109 | <%- first.push(1) -%> 110 | <%- end -%> 111 | <%- end -%> 112 | <%- elsif item.kind_of?(Numeric) or 113 | (convert_nums and ( 114 | item.to_i.to_s == item or 115 | item.to_f.to_s == item)) or 116 | (convert_bools and ['true', 'True', 'false', 'False'].include?(item)) or 117 | item.kind_of?(TrueClass) or item.kind_of?(FalseClass) -%> 118 | <%-# The item is a number or boolean -%> 119 | <%--%><%= item.to_s.downcase -%> 120 | <%- if prevtype != 'array' -%> 121 | <%--%><%= "\n" -%> 122 | <%- end -%> 123 | <%- elsif item.kind_of?(String) -%> 124 | <%-# The item is a string -%> 125 | <%--%><%= quote + item.to_s.gsub("\n", "\\n").gsub("\t", "\\t") + quote -%> 126 | <%- if prevtype != 'array' -%> 127 | <%--%><%= "\n" -%> 128 | <%- end -%> 129 | <%- else -%> 130 | <%-# The item is an array -%> 131 | <%- if item[0].kind_of?(Hash) -%> 132 | <%- item.each do |d| -%> 133 | <%--%><%= "\n" + indent * level + '[[' + prevkey.to_s + ']]' + "\n" -%> 134 | <%- 135 | _item.push(item) 136 | _prevkey.push(prevkey) 137 | _prevtype.push(prevtype) 138 | item = d 139 | prevtype = 'array' 140 | -%> 141 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 142 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 143 | <%- 144 | prevkey = _prevkey.pop() 145 | prevtype = _prevtype.pop() 146 | item = _item.pop() 147 | -%> 148 | <%- end -%> 149 | <%- else -%> 150 | <%--%><%= '[' -%> 151 | <%- item.each do |d| -%> 152 | <%- 153 | _item.push(item) 154 | _prevkey.push(prevkey) 155 | _prevtype.push(prevtype) 156 | item = d 157 | prevtype = 'array' 158 | -%> 159 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 160 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 161 | <%- 162 | prevkey = _prevkey.pop() 163 | prevtype = _prevtype.pop() 164 | item = _item.pop() 165 | -%> 166 | <%- if d != item.last -%> 167 | <%--%><%= ', ' -%> 168 | <%- end -%> 169 | <%- end -%> 170 | <%--%><%= ']' -%> 171 | <%- if prevtype != 'array' -%> 172 | <%--%><%= "\n" -%> 173 | <%- end -%> 174 | <%- end -%> 175 | <%- end -%> 176 | -------------------------------------------------------------------------------- /macros/toml_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to TOML format 3 | #} 4 | 5 | {%- macro toml_encode( 6 | item, 7 | convert_bools=false, 8 | convert_nums=false, 9 | first=[], 10 | indent=" ", 11 | level=0, 12 | prevkey="", 13 | prevtype="", 14 | quote='"') %} 15 | 16 | {%- if item is mapping %} 17 | {#- The item is a dict #} 18 | 19 | {#- First process all strings, numbers, booleans and lists #} 20 | {%- for key, val in item.iteritems() | sort -%} 21 | {%- if val is string or 22 | val is number or 23 | val in [True, False] or 24 | ( 25 | val is not mapping and 26 | val | length > 0 and 27 | val[0] is not mapping) %} 28 | 29 | {#- The value is a string, a number, or a list -#} 30 | {{ indent * level }}{{ key }}{{ " = " }}{{ toml_encode( 31 | val, 32 | convert_bools=convert_bools, 33 | convert_nums=convert_nums, 34 | first=first, 35 | indent=indent, 36 | level=level, 37 | prevkey=prevkey) }} 38 | {%- if first.append(1) %}{% endif %} 39 | {%- endif %} 40 | {%- endfor %} 41 | 42 | {#- Then process all data structures #} 43 | {%- for key, val in item.iteritems() | sort %} 44 | {%- if val is not string and 45 | val is not number and 46 | val not in [True, False] and 47 | ( 48 | val is mapping or 49 | val[0] is mapping) %} 50 | 51 | {%- set old_prevkey = prevkey %} 52 | {%- set old_level = level %} 53 | 54 | {%- if val is mapping %} 55 | {#- The val is a dict #} 56 | {%- if prevkey != "" and prevkey != key %} 57 | {%- set level = level + 1 %} 58 | {%- endif %} 59 | 60 | {%- set prevkey = (key if prevkey == "" else prevkey + "." + key) %} 61 | 62 | {%- if first | length > 0 -%} 63 | {{ "\n" }} 64 | {%- endif -%} 65 | 66 | {{ indent * level }}[{{ prevkey }}]{{ "\n" }} 67 | {%- elif val[0] is mapping %} 68 | {#- The val is a table #} 69 | {%- set prevkey = (key if prevkey == "" else prevkey + "." + key) %} 70 | {%- set level = level + 1 %} 71 | {%- endif -%} 72 | 73 | {{ toml_encode( 74 | val, 75 | convert_bools=convert_bools, 76 | convert_nums=convert_nums, 77 | first=first, 78 | indent=indent, 79 | level=level, 80 | prevkey=prevkey) }} 81 | 82 | {%- set prevkey = old_prevkey %} 83 | {%- set level = old_level %} 84 | {%- if first.append(1) %}{% endif %} 85 | {%- endif %} 86 | {%- endfor %} 87 | 88 | {%- elif item is number or 89 | (convert_nums and ( 90 | item | int | string == item or 91 | item | float | string == item)) or 92 | (convert_bools and item in ["true", "True", "false", "False"]) or 93 | item in [True, False] %} 94 | 95 | {#- The item is a number or boolean -#} 96 | {{ item | lower }} 97 | 98 | {%- if prevtype != "list" -%} 99 | {{ "\n" }} 100 | {%- endif -%} 101 | 102 | {%- elif item is string %} 103 | {#- The item is a string -#} 104 | {{ quote ~ item | replace("\n", "\\n") | replace("\t", "\\t") ~ quote }} 105 | 106 | {%- if prevtype != "list" -%} 107 | {{ "\n" }} 108 | {%- endif -%} 109 | 110 | {%- else %} 111 | {#- The item is a list #} 112 | {%- if item[0] is mapping %} 113 | {%- for d in item -%} 114 | {{ "\n" }}{{ indent * level }}[[{{ prevkey }}]]{{ "\n" }}{{ toml_encode( 115 | d, 116 | convert_bools=convert_bools, 117 | convert_nums=convert_nums, 118 | first=first, 119 | indent=indent, 120 | level=level) }} 121 | {%- endfor %} 122 | {%- else -%} 123 | {{ "[" }} 124 | 125 | {%- for d in item -%} 126 | {{ toml_encode( 127 | d, 128 | convert_bools=convert_bools, 129 | convert_nums=convert_nums, 130 | first=first, 131 | indent=indent, 132 | level=level, 133 | prevtype="list") }} 134 | 135 | {%- if not loop.last -%} 136 | {{ ", " }} 137 | {%- endif %} 138 | {%- endfor -%} 139 | 140 | {{ "]" }} 141 | 142 | {%- if prevtype != "list" -%} 143 | {{ "\n" }} 144 | {%- endif -%} 145 | 146 | {%- endif %} 147 | {%- endif %} 148 | {%- endmacro %} 149 | -------------------------------------------------------------------------------- /macros/xml_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to XML format 3 | #-%> 4 | <%- 5 | _item ||= Array.new 6 | _prev_list ||= Array.new 7 | _prevkey ||= Array.new 8 | first ||= Array.new 9 | indent ||= ' ' 10 | level ||= 0 11 | macro_path ||= 'macros/xml_encode_macro.erb' 12 | prevkey ||= nil 13 | -%> 14 | <%- if item.kind_of?(Hash) -%> 15 | <%-# The item is a hash -%> 16 | <%- prev_list = [0] -%> 17 | <%- item.sort.each do |key, val| -%> 18 | <%- if first.length > 0 and prev_list[0] == 0 -%> 19 | <%--%><%= "\n" -%> 20 | <%- end -%> 21 | <%- first.push(0) -%> 22 | <%- 23 | prev_list.insert(0, 0) 24 | prev_list.delete_at(1) 25 | -%> 26 | <%- if val == nil -%> 27 | <%--%><%= indent * level + '<' + key.to_s + '/>\n' -%> 28 | <%- elsif val.kind_of?(Array) -%> 29 | <%-# Only if val is an array -%> 30 | <%- 31 | _item.push(item) 32 | _prevkey.push(prevkey) 33 | _prev_list.push(prev_list) 34 | prev_list = [0] 35 | prevkey = key 36 | item = val 37 | -%> 38 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 39 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 40 | <%- 41 | prevkey = _prevkey.pop() 42 | prev_list = _prev_list.pop() 43 | item = _item.pop() 44 | -%> 45 | <%- 46 | prev_list.insert(0, 1) 47 | prev_list.delete_at(1) 48 | -%> 49 | <%- else -%> 50 | <%--%><%= indent * level + '<' + key.to_s + '>' -%> 51 | <%- 52 | _item.push(item) 53 | _prevkey.push(prevkey) 54 | _prev_list.push(prev_list) 55 | prev_list = [0] 56 | prevkey = key 57 | item = val 58 | level = level+1 59 | -%> 60 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 61 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 62 | <%- 63 | prevkey = _prevkey.pop() 64 | prev_list = _prev_list.pop() 65 | item = _item.pop() 66 | level = level-1 67 | -%> 68 | <%- if val.kind_of?(Hash) or val.kind_of?(Array) -%> 69 | <%--%><%= indent * level -%> 70 | <%- end -%> 71 | <%--%><%= '' -%> 72 | <%- if key == item.keys.sort.last -%> 73 | <%--%><%= "\n" -%> 74 | <%- end -%> 75 | <%- end -%> 76 | <%- end -%> 77 | <%- elsif item.kind_of?(Numeric) or item.kind_of?(String) or 78 | item.kind_of?(TrueClass) or item.kind_of?(FalseClass) -%> 79 | <%-# The item is a number, string or boolean -%> 80 | <%--%><%= item -%> 81 | <%- elsif item == nil -%> 82 | <%-# Item is a value of an empty element -%> 83 | <%- else -%> 84 | <%-# The item is an array -%> 85 | <%- item.each do |e| -%> 86 | <%--%><%= indent * level + '<' + prevkey + '>' -%> 87 | <%- 88 | _item.push(item) 89 | item = e 90 | level = level+1 91 | -%> 92 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 93 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 94 | <%- 95 | item = _item.pop() 96 | level = level-1 97 | -%> 98 | <%- if ! e.kind_of?(String) and ! e.kind_of?(Numeric) and e != nil -%> 99 | <%--%><%= indent * level -%> 100 | <%- end -%> 101 | <%--%><%= '' + "\n" -%> 102 | <%- end -%> 103 | <%- end -%> 104 | -------------------------------------------------------------------------------- /macros/xml_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to XML format 3 | #} 4 | 5 | {%- macro xml_encode( 6 | item, 7 | first=[], 8 | indent=" ", 9 | level=0, 10 | prevkey=none) %} 11 | 12 | {%- if item is mapping %} 13 | {#- The item is a dict #} 14 | 15 | {%- set prev_list = [0] %} 16 | 17 | {%- for key, val in item.iteritems() | sort -%} 18 | {%- if first | length > 0 and prev_list[0] == 0 -%} 19 | {{ "\n" }} 20 | {%- endif -%} 21 | 22 | {%- if first.append(0) %}{% endif %} 23 | {%- if prev_list.insert(0, 0) and prev_list.remove(1) %}{% endif %} 24 | 25 | {%- if val is none -%} 26 | {{ indent * level ~ "<" ~ key ~ " />\n" }} 27 | {%- elif val is sequence and val is not string and val is not mapping -%} 28 | {#- Only if val is a list -#} 29 | {{ xml_encode( 30 | val, 31 | first=first, 32 | indent=indent, 33 | level=level, 34 | prevkey=key) }} 35 | {%- if prev_list.insert(0, 1) and prev_list.remove(1) %}{% endif %} 36 | {%- else -%} 37 | {{ indent * level }}<{{ key }}>{{ xml_encode( 38 | val, 39 | indent=indent, 40 | level=level+1) }} 41 | 42 | {%- if val is not string and val is not number and val is not none -%} 43 | {{ indent * level }} 44 | {%- endif -%} 45 | 46 | 47 | 48 | {%- if loop.last -%} 49 | {{ "\n" }} 50 | {%- endif %} 51 | {%- endif %} 52 | {%- endfor %} 53 | 54 | {%- elif item is number or item is string or item in [True, False] %} 55 | {#- The item is a number, string or boolean -#} 56 | 57 | {{ item }} 58 | 59 | {%- elif item is none %} 60 | {#- Item is a value of an empty element #} 61 | 62 | {%- else %} 63 | {#- The item is a list #} 64 | 65 | {%- for e in item -%} 66 | {{ indent * level }}<{{ prevkey }}>{{ xml_encode( 67 | e, 68 | first=first, 69 | indent=indent, 70 | level=level+1, 71 | prevkey=prevkey) }} 72 | 73 | {%- if e is not string and e is not number and e is not none -%} 74 | {{ indent * level }} 75 | {%- endif -%} 76 | 77 | {{ "\n" }} 78 | {%- endfor %} 79 | {%- endif %} 80 | {%- endmacro %} 81 | -------------------------------------------------------------------------------- /macros/yaml_encode_macro.erb: -------------------------------------------------------------------------------- 1 | <%-# 2 | # ERB macro which converts Ruby data structure to YAML format 3 | #-%> 4 | <%- 5 | _item ||= Array.new 6 | _skip_indent ||= Array.new 7 | convert_bools ||= false 8 | convert_nums ||= false 9 | indent ||= ' ' 10 | level ||= 0 11 | macro_path ||= 'macros/yaml_encode_macro.erb' 12 | quote ||= '"' 13 | skip_indent ||= false 14 | -%> 15 | <%- if item.kind_of?(Hash) -%> 16 | <%-# The item is a hash -%> 17 | <%- item.sort.each do |key, val| -%> 18 | <%- if skip_indent and key == item.keys.sort.first -%> 19 | <%--%><%= ' ' -%> 20 | <%- else -%> 21 | <%--%><%= indent * level -%> 22 | <%- end -%> 23 | <%--%><%= key.to_s + ':' -%> 24 | <%- if ! val.kind_of?(String) and 25 | ! val.kind_of?(Numeric) and 26 | ! val.kind_of?(TrueClass) and 27 | ! val.kind_of?(FalseClass)-%> 28 | <%--%><%= "\n" -%> 29 | <%- end -%> 30 | <%- 31 | _item.push(item) 32 | item = val 33 | level = level+1 34 | -%> 35 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 36 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 37 | <%- 38 | level = level-1 39 | item = _item.pop() 40 | -%> 41 | <%- end -%> 42 | <%- if item.length == 0 -%> 43 | <%--%><%= indent * level + "{ }\n" -%> 44 | <%- end -%> 45 | <%- elsif item.kind_of?(Numeric) or 46 | (convert_nums and ( 47 | item.to_i.to_s == item or 48 | item.to_f.to_s == item)) or 49 | (convert_bools and ['true', 'True', 'false', 'False'].include?(item)) or 50 | item.kind_of?(TrueClass) or item.kind_of?(FalseClass) -%> 51 | <%-# The item is a number or boolean -%> 52 | <%--%><%= ' ' + item.to_s.downcase + "\n" -%> 53 | <%- elsif item.kind_of?(String) -%> 54 | <%-# The item is a string -%> 55 | <%--%><%= ' ' + 56 | quote + 57 | item.gsub('\\', '\\\\').gsub(quote, '\\' + quote) + 58 | quote + "\n" -%> 59 | <%- else -%> 60 | <%-# The item is an array -%> 61 | <%- item.each do |n| -%> 62 | <%--%><%= indent * level + '-' -%> 63 | <%- if ! n.kind_of?(String) and 64 | ! n.kind_of?(Numeric) and 65 | ! n.kind_of?(Hash) -%> 66 | <%--%><%= "\n" -%> 67 | <%- end -%> 68 | <%- 69 | _item.push(item) 70 | _skip_indent.push(skip_indent) 71 | 72 | item = n 73 | level = level+1 74 | skip_indent = true 75 | -%> 76 | <%--%><%= ERB.new(IO.read(macro_path), nil, '-', '_erbout_' + 77 | rand(36**20).to_s(36)).result(OpenStruct.new().send(:binding)) -%> 78 | <%- 79 | skip_indent = _skip_indent.pop() 80 | level = level-1 81 | item = _item.pop() 82 | -%> 83 | <%- end -%> 84 | <%- end -%> 85 | -------------------------------------------------------------------------------- /macros/yaml_encode_macro.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Jinja2 macro which converts Python data structure to YAML format 3 | #} 4 | 5 | {%- macro yaml_encode( 6 | item, 7 | convert_bools=false, 8 | convert_nums=false, 9 | indent=" ", 10 | level=0, 11 | quote='"', 12 | skip_indent=false) %} 13 | 14 | {%- if item is mapping %} 15 | {#- The item is a dict #} 16 | {%- for key, val in item.iteritems() | sort -%} 17 | {%- if skip_indent and loop.first -%} 18 | {{ " " }} 19 | {%- else -%} 20 | {{ indent * level }} 21 | {%- endif -%} 22 | 23 | {{ key }}: 24 | 25 | {%- if val is not string and val is not number -%} 26 | {{ "\n" }} 27 | {%- endif -%} 28 | 29 | {{ yaml_encode( 30 | val, 31 | convert_bools=convert_bools, 32 | convert_nums=convert_nums, 33 | indent=indent, 34 | level=level+1, 35 | quote=quote) }} 36 | {%- else -%} 37 | {{ indent * level + "{ }\n" }} 38 | {%- endfor %} 39 | 40 | {%- elif item is number or 41 | (convert_nums and ( 42 | item | int | string == item or 43 | item | float | string == item)) or 44 | (convert_bools and item in ["true", "True", "false", "False"]) or 45 | item in [True, False] %} 46 | 47 | {#- The item is a number or boolean -#} 48 | {{ " " ~ item | lower ~ "\n" }} 49 | 50 | {%- elif item is string %} 51 | {#- The item is a string -#} 52 | {{ " " + 53 | quote + 54 | item | replace("\\", "\\\\") | replace(quote, "\\" + quote) + 55 | quote + "\n" }} 56 | 57 | {%- else %} 58 | {#- The item is a list #} 59 | {%- for n in item -%} 60 | {{ indent * level }}- 61 | {%- if n is not string and 62 | n is not number and 63 | n is not mapping -%} 64 | {{ "\n" }} 65 | {%- endif -%} 66 | {{ yaml_encode( 67 | n, 68 | convert_bools=convert_bools, 69 | convert_nums=convert_nums, 70 | indent=indent, 71 | level=level+1, 72 | quote=quote, 73 | skip_indent=true) }} 74 | {%- endfor %} 75 | {%- endif %} 76 | {%- endmacro %} 77 | -------------------------------------------------------------------------------- /puppet_apply.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Apply Puppet manifests 4 | puppet apply \ 5 | --test \ 6 | --confdir=. \ 7 | --ssldir=/tmp/puppet_ssl \ 8 | --templatedir=./templates \ 9 | $@ \ 10 | ./site.pp 11 | 12 | # Or you can use ERB directly: 13 | # $ erb -r ostruct -T '-' 'ini_data={"aaa" => "bbb", "ccc" => {"ddd" => "eee"}}' ./templates/test.ini.erb 14 | -------------------------------------------------------------------------------- /site.pp: -------------------------------------------------------------------------------- 1 | node default { 2 | ### Apache 3 | $apache_data = hiera('apache_data') 4 | 5 | file { '/tmp/test.apache' : 6 | ensure => present, 7 | content => template('test.apache.erb'), 8 | } 9 | 10 | ### Erlang 11 | $erlang_data = hiera('erlang_data') 12 | 13 | file { '/tmp/test.erlang' : 14 | ensure => present, 15 | content => template('test.erlang.erb'), 16 | } 17 | 18 | ### INI 19 | $ini_data = hiera('ini_data') 20 | 21 | file { '/tmp/test.ini' : 22 | ensure => present, 23 | content => template('test.ini.erb'), 24 | } 25 | 26 | file { '/tmp/test.simple' : 27 | ensure => present, 28 | content => template('test.ini_simple.erb'), 29 | } 30 | 31 | 32 | ### JSON 33 | $json_data = hiera('json_data') 34 | 35 | file { '/tmp/test.json' : 36 | ensure => present, 37 | content => template('test.json.erb'), 38 | } 39 | 40 | ### Logstash 41 | $json_data = hiera('logstash_data') 42 | 43 | file { '/tmp/test.logstash' : 44 | ensure => present, 45 | content => template('test.logstash.erb'), 46 | } 47 | 48 | ### TOML 49 | $toml_data = hiera('toml_data') 50 | 51 | file { '/tmp/test.toml' : 52 | ensure => present, 53 | content => template('test.toml.erb'), 54 | } 55 | 56 | ### XML 57 | $xml_data = hiera('xml_data') 58 | 59 | file { '/tmp/test.xml' : 60 | ensure => present, 61 | content => template('test.xml.erb'), 62 | } 63 | 64 | ### YAML 65 | $yaml_data = hiera('yaml_data') 66 | 67 | file { '/tmp/test.yaml' : 68 | ensure => present, 69 | content => template('test.yaml.erb'), 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /site.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Apache encode example 4 | hosts: all 5 | vars_files: 6 | - vars/apache_test.yaml 7 | tasks: 8 | - name: Create test.apache file 9 | template: 10 | src: templates/test.apache.j2 11 | dest: /tmp/test.apache 12 | tags: 13 | - apache 14 | 15 | - name: Erlang encode example 16 | hosts: all 17 | vars_files: 18 | - vars/erlang_test.yaml 19 | tasks: 20 | - name: Create test.erlang file 21 | template: 22 | src: templates/test.erlang.j2 23 | dest: /tmp/test.erlang 24 | tags: 25 | - erlang 26 | 27 | - name: INI encode example 28 | hosts: all 29 | vars_files: 30 | - vars/ini_test.yaml 31 | tasks: 32 | - name: Create test.ini file 33 | template: 34 | src: templates/test.ini.j2 35 | dest: /tmp/test.ini 36 | tags: 37 | - ini 38 | 39 | - name: Simplified INI encode example 40 | hosts: all 41 | vars_files: 42 | - vars/ini_test.yaml 43 | tasks: 44 | - name: Create test.simple file 45 | template: 46 | src: templates/test.ini_simple.j2 47 | dest: /tmp/test.ini_simple 48 | tags: 49 | - simple 50 | 51 | - name: JSON encode example 52 | hosts: all 53 | vars_files: 54 | - vars/json_test.yaml 55 | tasks: 56 | - name: Create test.json file 57 | template: 58 | src: templates/test.json.j2 59 | dest: /tmp/test.json 60 | tags: 61 | - json 62 | 63 | - name: Logstash encode example 64 | hosts: all 65 | vars_files: 66 | - vars/logstash_test.yaml 67 | tasks: 68 | - name: Create test.logstash file 69 | template: 70 | src: templates/test.logstash.j2 71 | dest: /tmp/test.logstash 72 | tags: 73 | - logstash 74 | 75 | - name: TOML encode example 76 | hosts: all 77 | vars_files: 78 | - vars/toml_test.yaml 79 | tasks: 80 | - name: Create test.toml file 81 | template: 82 | src: templates/test.toml.j2 83 | dest: /tmp/test.toml 84 | tags: 85 | - toml 86 | 87 | - name: XML encode example 88 | hosts: all 89 | vars_files: 90 | - vars/xml_test.yaml 91 | tasks: 92 | - name: Create test.xml file 93 | template: 94 | src: templates/test.xml.j2 95 | dest: /tmp/test.xml 96 | tags: 97 | - xml 98 | 99 | - name: YAML encode example 100 | hosts: all 101 | vars_files: 102 | - vars/yaml_test.yaml 103 | tasks: 104 | - name: Create test.yaml file 105 | template: 106 | src: templates/test.yaml.j2 107 | dest: /tmp/test.yaml 108 | tags: 109 | - yaml 110 | -------------------------------------------------------------------------------- /templates/test.apache.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Puppet. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | <%- 8 | item = @apache_data || (apache_data.kind_of?(String) ? eval(apache_data) : apache_data) 9 | macro_path = 'macros/apache_encode_macro.erb' 10 | -%> 11 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 12 | -------------------------------------------------------------------------------- /templates/test.apache.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Ansible. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | {% from "macros/apache_encode_macro.j2" import apache_encode with context -%} 8 | 9 | {{ apache_encode(apache_data) }} 10 | -------------------------------------------------------------------------------- /templates/test.erlang.erb: -------------------------------------------------------------------------------- 1 | % 2 | % This file is managed by Puppet. 3 | % Do not edit this file manually. 4 | % Any changes will be automatically reverted. 5 | % 6 | 7 | <%- 8 | item = @erlang_data || (erlang_data.kind_of?(String) ? eval(erlang_data) : erlang_data) 9 | macro_path = 'macros/erlang_encode_macro.erb' 10 | -%> 11 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 12 | -------------------------------------------------------------------------------- /templates/test.erlang.j2: -------------------------------------------------------------------------------- 1 | % 2 | % This file is managed by Ansible. 3 | % Do not edit this file manually. 4 | % Any changes will be automatically reverted. 5 | % 6 | 7 | {% from "macros/erlang_encode_macro.j2" import erlang_encode with context -%} 8 | 9 | {{ erlang_encode(erlang_data) }} 10 | -------------------------------------------------------------------------------- /templates/test.ini.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Puppet. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | <%- 8 | item = @ini_data || (ini_data.kind_of?(String) ? eval(ini_data) : ini_data) 9 | -%> 10 | <%= ERB.new(IO.read('macros/ini_encode_macro.erb'), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 11 | -------------------------------------------------------------------------------- /templates/test.ini.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Ansible. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | {% from "macros/ini_encode_macro.j2" import ini_encode with context -%} 8 | 9 | {{ ini_encode(ini_data) }} 10 | -------------------------------------------------------------------------------- /templates/test.ini_simple.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Puppet. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | <%- 8 | item = @ini_data || (ini_data.kind_of?(String) ? eval(ini_data) : ini_data) 9 | delimiter = ' ' 10 | section_is_comment = true 11 | -%> 12 | <%= ERB.new(IO.read('macros/ini_encode_macro.erb'), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 13 | -------------------------------------------------------------------------------- /templates/test.ini_simple.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Ansible. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | {% from "macros/ini_encode_macro.j2" import ini_encode with context -%} 8 | 9 | {{ ini_encode(ini_data, section_is_comment=true, delimiter=" ") }} 10 | -------------------------------------------------------------------------------- /templates/test.json.erb: -------------------------------------------------------------------------------- 1 | <%- 2 | item = @json_data || (json_data.kind_of?(String) ? eval(json_data) : json_data) 3 | macro_path = 'macros/json_encode_macro.erb' 4 | -%> 5 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 6 | -------------------------------------------------------------------------------- /templates/test.json.j2: -------------------------------------------------------------------------------- 1 | {% from "macros/json_encode_macro.j2" import json_encode with context -%} 2 | 3 | {{ json_encode(json_data) }} 4 | -------------------------------------------------------------------------------- /templates/test.logstash.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Puppet. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | <%- 8 | item = @logstash_data || (logstash_data.kind_of?(String) ? eval(logstash_data) : logstash_data) 9 | macro_path = 'macros/logstash_encode_macro.erb' 10 | -%> 11 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 12 | -------------------------------------------------------------------------------- /templates/test.logstash.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Ansible. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | {% from "macros/logstash_encode_macro.j2" import logstash_encode with context -%} 8 | 9 | {{ logstash_encode(logstash_data) }} 10 | -------------------------------------------------------------------------------- /templates/test.toml.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Puppet. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | <%- 8 | item = @toml_data || (toml_data.kind_of?(String) ? eval(toml_data) : toml_data) 9 | macro_path = 'macros/toml_encode_macro.erb' 10 | -%> 11 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 12 | -------------------------------------------------------------------------------- /templates/test.toml.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Ansible. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | {% from "macros/toml_encode_macro.j2" import toml_encode with context -%} 8 | 9 | {{ toml_encode(toml_data) }} 10 | -------------------------------------------------------------------------------- /templates/test.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | <%- 12 | item = @xml_data || (xml_data.kind_of?(String) ? eval(xml_data) : xml_data) 13 | macro_path = 'macros/xml_encode_macro.erb' 14 | -%> 15 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 16 | -------------------------------------------------------------------------------- /templates/test.xml.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | {% from "macros/xml_encode_macro.j2" import xml_encode with context -%} 12 | 13 | {{ xml_encode(xml_data) }} 14 | -------------------------------------------------------------------------------- /templates/test.yaml.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Puppet. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | <%- 8 | item = @yaml_data || (yaml_data.kind_of?(String) ? eval(yaml_data) : yaml_data) 9 | macro_path = 'macros/yaml_encode_macro.erb' 10 | -%> 11 | <%= ERB.new(IO.read(macro_path), nil, '-', '_erbout1').result(OpenStruct.new().send(:binding)) -%> 12 | -------------------------------------------------------------------------------- /templates/test.yaml.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This file is managed by Ansible. 3 | # Do not edit this file manually. 4 | # Any changes will be automatically reverted. 5 | # 6 | 7 | {% from "macros/yaml_encode_macro.j2" import yaml_encode with context -%} 8 | 9 | {{ yaml_encode(yaml_data) }} 10 | -------------------------------------------------------------------------------- /vars/apache_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apache_data: 4 | content: 5 | - options: 6 | - ServerName: localhost 7 | - Listen: 8080 8 | - PidFile: tmp/httpd.pid 9 | - LockFile: tmp/accept.lock 10 | - options: 11 | - "# This is an example of a comment": "" 12 | - LoadModule: 13 | - authz_host_module 14 | - /usr/libexec/apache2/mod_authz_host.so 15 | - LoadModule: 16 | - dir_module 17 | - /usr/libexec/apache2/mod_dir.so 18 | - LoadModule: 19 | - env_module 20 | - /usr/libexec/apache2/mod_env.so 21 | - LoadModule: 22 | - mime_module 23 | - /usr/libexec/apache2/mod_mime.so 24 | - LoadModule: 25 | - log_config_module 26 | - /usr/libexec/apache2/mod_log_config.so 27 | - LoadModule: 28 | - rewrite_module 29 | - /usr/libexec/apache2/mod_rewrite.so 30 | - LoadModule: 31 | - php5_module 32 | - /usr/local/opt/php53/libexec/apache2/libphp5.so 33 | - LogLevel: info 34 | - options: 35 | - ErrorLog: "|cat" 36 | - LogFormat: 37 | - "%h %l %u %t \"%r\" %>s %b" 38 | - common 39 | - CustomLog: 40 | - "|cat" 41 | - common 42 | - options: 43 | - DocumentRoot: build 44 | - sections: 45 | - name: Directory 46 | param: build 47 | content: 48 | - options: 49 | - AllowOverride: all 50 | - Order: allow,deny 51 | - Allow: 52 | - from 53 | - all 54 | - options: 55 | - AddType: 56 | - application/x-httpd-php 57 | - .php 58 | - DirectoryIndex: 59 | - index.html 60 | - index.php 61 | - options: 62 | - SetEnv: 63 | - LOCAL_SERVER 64 | - true 65 | -------------------------------------------------------------------------------- /vars/erlang_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | erlang_data: 4 | - rabbit: 5 | - tcp_listeners: 6 | - '"127.0.0.1"': 5672 7 | - ssl_listeners: 8 | - 5671 9 | - ssl_options: 10 | - cacertfile: /path/to/testca/cacert.pem 11 | - certfile: /path/to/server/cert.pem 12 | - keyfile: /path/to/server/key.pem 13 | - verify: verify_peer 14 | - fail_if_no_peer_cert: true 15 | -------------------------------------------------------------------------------- /vars/ini_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ini_data: 4 | var1: val1 5 | var2: val2 6 | section1: 7 | aaa: 8 | - asdf 9 | - zxcv 10 | bbb: 123 11 | ccc: 'true' 12 | section2: 13 | ddd: asdfasd 14 | eee: 1234 15 | fff: 'false' 16 | -------------------------------------------------------------------------------- /vars/json_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | json_data: 4 | string: This is a string 5 | number: 123 6 | boolean: 'true' 7 | dict: 8 | aaa: bbb 9 | ccc: true 10 | list: 11 | - eee 12 | - fff 13 | complex: 14 | ggg: 15 | - hhh 16 | - iii: jjj 17 | -------------------------------------------------------------------------------- /vars/logstash_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | logstash_data: 4 | - :input: 5 | - :file: 6 | path: /var/log/messages 7 | type: syslog 8 | - :file: 9 | path: /var/log/apache/access.log 10 | type: apache 11 | - :filter: 12 | - ':if [type] == "apache"': 13 | - ':if [status] =~ /^5\d\d/': 14 | :nagios: 15 | codes: plain 16 | workers: 1 17 | - ':else if [status] =~ /^4\d\d/': 18 | :elasticsearch: 19 | xxx: 20 | aaa: bbb 21 | ccc: ddd 22 | hosts: 23 | - es-server1 24 | - es-server2 25 | query: "type:start AND operation:%{[opid]}" 26 | fields: 27 | - "@timestamp" 28 | - started 29 | - :output: 30 | - :file: 31 | path: /var/log/%{type}.%{+yyyy.MM.dd.HH} 32 | - :statsd: 33 | increment: apache.%{[response][status]} 34 | -------------------------------------------------------------------------------- /vars/toml_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | toml_data: 4 | title: TOML Example 5 | owner: 6 | name: Tom Preston-Werner 7 | organization: GitHub 8 | bio: "GitHub Cofounder & CEO\nLikes tater tots and beer." 9 | dob: "1979-05-27T07:32:00Z" 10 | database: 11 | server: 192.168.1.1 12 | ports: [ 8001, 8001, 8002 ] 13 | connection_max: 5000 14 | enabled: true 15 | servers: 16 | alpha: 17 | ip: 10.0.0.1 18 | dc: eqdc10 19 | beta: 20 | ip: 10.0.0.2 21 | dc: eqdc10 22 | country: "中国" 23 | clients: 24 | data: [ ["gamma", "delta"], [1, 2] ] 25 | hosts: [ "alpha", "omega" ] 26 | products: 27 | - 28 | name: Hammer 29 | sku: 738594937 30 | - 31 | name: Nail 32 | sku: 284758393 33 | color: gray 34 | -------------------------------------------------------------------------------- /vars/xml_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | xml_data: 4 | root: 5 | elem1: asd 6 | elem2: 7 | - asd 8 | - zxc 9 | with_attrs: 10 | 'elem3 attr1="val1" attr2=val2': 123 11 | 'elem4 attr3="val3"': 12 | - Value 1 13 | - elem5: 14 | - Value 2 15 | - Value 3 16 | -------------------------------------------------------------------------------- /vars/yaml_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | yaml_data: 4 | string: This is a string 5 | number: 123 6 | boolean: 'true' 7 | dict: 8 | aaa: bbb 9 | ccc: true 10 | list: 11 | - eee 12 | - fff 13 | complex: 14 | ggg: 15 | - hhh 16 | - iii: jjj 17 | -------------------------------------------------------------------------------- /yaml_converter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | from argparse import RawTextHelpFormatter 4 | from jinja2 import Template 5 | from yaml import load 6 | import argparse 7 | import sys 8 | 9 | 10 | def parse_arguments(): 11 | description = 'YAML converter' 12 | epilog = ( 13 | "Examples:\n" 14 | " $ %(prog)s -f apache -v apache_data -y ./vars/apache_test.yaml\n" 15 | " $ %(prog)s -f json -v json_data -y ./vars/json_test.yaml") 16 | 17 | parser = argparse.ArgumentParser( 18 | description=description, 19 | epilog=epilog, 20 | formatter_class=RawTextHelpFormatter) 21 | parser.add_argument( 22 | '-f', '--format', 23 | metavar='FORMAT', 24 | choices=['apache', 'erlang', 'ini', 'json', 'logstash', 'toml', 'xml', 'yaml'], 25 | required=True, 26 | help='output format') 27 | parser.add_argument( 28 | '-p', '--path', 29 | metavar='PATH', 30 | default='.', 31 | help='path to the macros directory (default: .)') 32 | parser.add_argument( 33 | '-v', '--var', 34 | metavar='NAME', 35 | help='read data from certain YAML variable') 36 | parser.add_argument( 37 | '-y', '--yaml', 38 | metavar='FILE', 39 | dest='yaml_fh', 40 | type=argparse.FileType('r'), 41 | default='-', 42 | help='YAML file to convert (default: -)') 43 | 44 | return (parser.parse_args(), parser) 45 | 46 | 47 | def main(): 48 | # Parse command line arguments 49 | (args, parser) = parse_arguments() 50 | 51 | # Load the YAML data to Python data structure 52 | yaml_data = load(args.yaml_fh) 53 | args.yaml_fh.close() 54 | 55 | if args.var: 56 | yaml_data = yaml_data[args.var] 57 | 58 | # Read Jinja2 template as text 59 | template_fh = open( 60 | '%s/macros/%s_encode_macro.j2' % (args.path, args.format)) 61 | template_text = template_fh.read() 62 | template_fh.close() 63 | 64 | # Create Jinja2 template object 65 | t = Template(template_text) 66 | # Convert the YAML data to the final format 67 | encode_method = getattr(t.module, '%s_encode' % args.format) 68 | output = encode_method(yaml_data) 69 | 70 | # Print the result 71 | sys.stdout.write(output.encode('utf8')) 72 | 73 | 74 | if __name__ == '__main__': 75 | main() 76 | -------------------------------------------------------------------------------- /yaml_converter.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'erb' 4 | require 'optparse' 5 | require 'ostruct' 6 | require 'yaml' 7 | 8 | def parse_arguments 9 | args = OpenStruct.new 10 | 11 | # Default values 12 | args.format = nil 13 | args.help = false 14 | args.path = '.' 15 | args.var = nil 16 | args.yaml_file = nil 17 | 18 | options = OptionParser.new do |opts| 19 | opts.program_name = $PROGRAM_NAME 20 | opts.banner = "usage: #{opts.program_name} " \ 21 | '[-h] -f FORMAT [-p PATH] [-v NAME] [-y FILE]' 22 | 23 | opts.separator('') 24 | opts.separator('YAML converter') 25 | opts.separator('') 26 | opts.separator('optional arguments:') 27 | 28 | opts.on( 29 | '-f', '--format FORMAT', 30 | 'output format') do |f| 31 | args.format = f 32 | end 33 | 34 | opts.on( 35 | '-h', '--help', 36 | 'show this help message and exit') do |h| 37 | args.help = h 38 | end 39 | 40 | opts.on( 41 | '-p', '--path PATH', 42 | 'path to the macros directory (default: .)') do |p| 43 | args.path = p 44 | end 45 | 46 | opts.on( 47 | '-v', '--var NAME', 48 | 'read data from certain YAML variable') do |v| 49 | args.var = v 50 | end 51 | 52 | opts.on( 53 | '-y', '--yaml FILE', 54 | 'YAML file to convert (default: -)') do |y| 55 | args.yaml_file = y 56 | end 57 | 58 | opts.separator('') 59 | opts.separator('Examples:') 60 | opts.separator(" $ #{opts.program_name} -f apache -v apache_data -y " \ 61 | './vars/apache_test.yaml') 62 | opts.separator(" $ #{opts.program_name} -f json -v json_data -y " \ 63 | './vars/json_test.yaml') 64 | end 65 | 66 | options.parse! 67 | 68 | return args, options 69 | end 70 | 71 | def main 72 | # Parse command line arguments 73 | args, options = parse_arguments 74 | 75 | # Check if help should be displayed 76 | if args.help 77 | print options.help 78 | exit 79 | end 80 | 81 | # Check if format was specified 82 | if args.format.nil? 83 | print options.help 84 | abort("\nERROR: Format not specified.") 85 | end 86 | 87 | # Check if specified format is supported 88 | formats = %w(apache erlang ini json toml xml yaml) 89 | unless formats.include?(args.format) 90 | abort('ERROR: Unsuported format. Suported formats are: ' + 91 | formats.join(', ')) 92 | end 93 | 94 | if args.yaml_file.nil? 95 | # Read data from pipeline 96 | yaml_input = ARGF.read 97 | yaml_load_fnc = YAML.method(:load) 98 | else 99 | # Check if the YAML file exists 100 | abort('ERROR: YAML file not found.') unless File.exist?(args.yaml_file) 101 | yaml_input = args.yaml_file 102 | yaml_load_fnc = YAML.method(:load_file) 103 | end 104 | 105 | # Convert the YAML data to the Ruby data structure 106 | if args.var.nil? 107 | item = yaml_load_fnc.call(yaml_input) 108 | else 109 | item = yaml_load_fnc.call(yaml_input)[args.var] 110 | end 111 | 112 | # Check if the macro file exists 113 | macro_path = "#{args.path}/macros/#{args.format}_encode_macro.erb" 114 | abort('ERROR: Macro file not found.') unless File.exist?(macro_path) 115 | 116 | # Convert the YAML data to the final format 117 | binding = OpenStruct.new.send(:binding) 118 | print ERB.new(IO.read(macro_path), nil, '-', '_erbout0').result(binding) 119 | end 120 | 121 | main if __FILE__ == $PROGRAM_NAME 122 | --------------------------------------------------------------------------------