forked from cloudwan/gohan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
extension.rst
1244 lines (889 loc) · 31.2 KB
/
extension.rst
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
==============
Extension
==============
You can add additional logic using Gohan Extension.
Extensions has properties:
- id identity of the code
- code contents of code
- code_type javascript, go and gohan script (DSL) are supported
- url placement of code. currenty, file://, http:// and https:// schemes are supported
- path resource path to execute code
Example Code
.. code-block:: yaml
extensions:
- code: console.log(Object.keys(context));
id: test
path: /v2.0/.*
Javascript Code block
---------------------
In the gohan extension code, you need to register context using
gohan_register_handler function.
gohan_register_handler talkes event_type (string)_ and handler (function(context)).
.. code-block:: javascript
gohan_register_handler("pre_show", function(context){
context.resp = "pre_show event"
});
gohan_register_handler("pre_update", function(context){
context.resp = "pre_update event "
});
context has following items
context.schema : schema information
context.path : url path
context.params : query params
context.role : user role
context.auth : auth_context information
context.http_request : Go HTTP request object
context.http_response : Go HTTP response writer object
Build in exception types
------------------------
In an effort to simplify writing extensions for validation Gohan supports
throwing some exceptions and handles them internally.
Gohan provides the following exception types.
- BaseException(msg)
The base type of exception, should never be raised as itself, only extended.
- CustomException(msg, code)
A BaseException with an additional code property. When thrown will result in
an http response with the provided code and message being written.
One can extend the CustomException. An example follows.
.. code-block:: javascript
function ValidationException(msg) {
CustomException.call(this, msg, 400);
this.name = "ValidationException";
}
ValidationException.prototype = Object.create(CustomException.prototype);
.. _`gohan built in functions`:
Build in javascript functions
-----------------------------
Gohan extension supports some build-in functions.
- ``gohan_log_critical(message)``
- ``gohan_log_error(message)``
- ``gohan_log_warning(message)``
- ``gohan_log_notice(message)``
- ``gohan_log_info(message)``
- ``gohan_log_debug(message)``
log ``message`` in Gohan log.
``gohan_log_<lowercase level>(message)`` is equivalent to
``gohan_log(MODULE, LOG_LEVEL.<uppercase level>, message)``.
- ``gohan_log(module, log_level, message)``
log ``message`` in Gohan log (general version).
- ``module``
The module to be used for logging. You can use ``LOG_MODULE`` for
the current log module. See ``gohan_log_module_push``.
- ``log_level``
One of ``LOG_LEVEL.CRITICAL``, ``LOG_LEVEL.ERROR``,
``LOG_LEVEL.WARNING``, ``LOG_LEVEL.NOTICE``, ``LOG_LEVEL.INFO``,
``LOG_LEVEL.DEBUG``.
Example usage::
gohan_log(LOG_MODULE, DEBUG, "It works");
This will print something like the following::
17:52:40.921 gohan.extension.network.post_list_in_transaction DEBUG It works
- ``gohan_log_module_push(new_module) : <old log module>``
Appends ``new_module`` to the current ``LOG_MODULE``.
- ``gohan_log_module_restore(old_module)``
Restores ``LOG_MODULE`` to ``old_module``. Example usage::
old_module = gohan_log_module_push("low_level");
try {
...
} finally {
gohan_restore_log_module(old_module)
}
- gohan_http(method, url, headers, data, options)
fetch data from url
method : GET | POST | PUT | DELETE
url : destination url
headers : additional headers (eg. AUTH_TOKEN)
data : post or put data
options : dictionary of options for http client
opaque : boolean - whether to parse URL or to treat it as raw
- gohan_config(key, default_value)
get value from Gohan config. If key is not found, default value is returned.
Key should be specified as
`JSON Pointer <http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07>`_.
- gohan_db_list(transaction, schema_id, filter_object[, order_key[, limit[, offset]]])
retrive all data from database
- gohan_db_fetch(transaction, schema_id, id, tenant_id)
get one data from db
- gohan_db_query(transaction, schema_id, query_string, arguments)
Retrieve data with a raw query
- transaction: The transaction to use. When null will use a new one.
- schema_id: The ID of the schema of which the query result populates instances
- query_string: Raw query string such as a SQL SELECT query
- You can put a "?" as the placeholder of variables in your query string
- arguments: An array of actual values that replace place holders in query_string
- gohan_db_create(transaction, schema_id, object)
create data in db
- gohan_db_update(transaction, schema_id, object)
update data in db
- gohan_db_state_update(transaction, schema_id, object)
update data in db without informing etcd
- gohan_db_delete(transaction, schema_id, object)
delete data in db
- gohan_db_transaction()
start a new DB transaction. You are responsible for managing tranansactions created by this function. Call .Close() or .Commit() after using the return value.
- gohan_model_list(context, schema_id, filter)
Retrieve data through Gohan.
- context: You need to have transaction in this dictionary which you can get from given context
- schema_id: The id of the schema of the objects we want to retrieve.
- filter: How to filter retrieved objects. Should be a dictionary with each key being either:
- A property of the schema we are retrieving. Then the value has to either be a string or an array of strings.
The response is then filtered by removing all entries that do not have the value for the given key in the provided array.
- Any of the strings 'sort_key', 'sort_order', 'limit', 'offset'. These are interpreted with their values as query parameters.
- gohan_model_fetch(context, schema_id, resource_ids)
Retrieve a specific resource through Gohan.
- context: You need to have transaction in this dictionary which you can get from given context
- schema_id: The id of the schema of the object we want to retrieve.
- resource_id: The id of the object we want to retrieve.
- tenant_ids: allowed tenant id
- gohan_model_create(context, schema_id, data)
Create an object through Gohan.
- context: You need to have transaction in this dictionary which you can get from given context
- schema_id: The id of the schema of the object we want to create.
- data: The data needed to create the object, in the form of a dictionary.
- gohan_model_update(context, schema_id, resource_id, data, tenant_ids)
Update an object through Gohan.
- context: You need to have transaction in this dictionary which you can get from given context
- schema_id: The id of the schema of the object we want to update.
- resource_id: The id of the object we want to update.
- data: The data needed to update the object, in the form of a dictionary.
- tenant_ids: allowed tenant id
- gohan_model_delete(context, schema_id, resource_id)
Delete an object through Gohan.
- context: You need to have transaction in this dictionary which you can get from given context
- schema_id: The id of the schema of the object we want to delete.
- resource_id: The id of the object we want to delete.
- gohan_schemas()
returns all registered schemas
- gohan_schema_url(schema)
returns the url for the schema
- gohan_policies()
returns all policies
- gohan_uuid()
generate uuid v4
- gohan_sleep(time)
sleep time (ms)
- gohan_execute(comand_name, args)
execute shell command
- gohan_template(template_string, variables)
apply go style template
- gohan_netconf_open(hostname, username)
open netconf session.
(Note: you need set up ssh key configuraion
on both of gohan and target node.)
In gohan, you need to setup ssh/key_file
configuraion.
- gohan_netconf_exec(session, command)
execute netconf command
- gohan_netconf_close(session)
close netconf session
- gohan_ssh_open(hostname, username)
open ssh session.
(Note: you need set up ssh key configuraion
on both of gohan and target node.)
In gohan, you need to setup ssh/key_file
configuraion.
- gohan_ssh_exec(session, command)
execute command on ssh session
- gohan_ssh_close(session)
close ssh session
- require(module)
Dynamically load modules
- gohan_file_list(dir)
List files in dir
- gohan_file_read(path)
Read file from path
- gohan_file_dir(path)
Check if dir
.. _event:
Event
----------------
- pre_list
list event before db operation
context.response contains response data.
You can also update response here
Note you can skip db operation if you set context response in here
- pre_list_in_transaction
same as pre_list but executed in the db transaction
context.transaction contains transaction object for db operation
id : request id
context.response contains response data.
You can also update response here
- post_list_in_transaction
same as post_list but executed in the db transaction
context.transaction contains transaction object for db operation
id : request id
context.response contains response data.
You can also update response here
- post_list
list event after db operation.
context.response contains response data.
You can also update response here
- pre_show
show event before db access
id : request id
context.response contains response data.
You can also update response here
Note you can skip db operation if you set context response in here
- pre_show_in_transaction
same as pre_show but executed in the db transaction
context.transaction contains transaction object for db operation
id : request id
context.response contains response data.
You can also update response here
- post_show_in_transaction
same as post_show but executed in the db transaction
context.transaction contains transaction object for db operation
id : request id
context.response contains response data.
You can also update response here
- post_show
show event after db operation
id : request id
context.response contains response data.
You can also update response here
- pre_create
executed before creation
Mainly used for validation purpose
context.resource contains user input data
Note you can skip db operation if you set context response in here
- pre_create_in_transaction
same as pre_create but executed in the db transaction
context.transaction contains transaction object for db operation
- post_create_in_transaction
after creation in transaction
- post_create
after create
context.response contains response data.
context.transaction contains transaction object for db operation
- pre_update
executed before update
Mainly used for validation purpose
context.resource contains user input data
Note you can skip db operation if you set context response in here
- pre_update_in_transaction
same as pre_update but executed in the db transaction
context.transaction contains transaction object for db operation
- post_update_in_transaction
after creation in transaction
- post_update
after update
context.response contains response data.
context.transaction contains transaction object for db operation
- pre_delete
executed before delete
Mainly used for validation purpose
context.id contains resource id we are trying to delete
context.transaction contains transaction object for db operation
- pre_delete_in_transaction
same as pre_delete but executed in the db transaction
context.transaction contains transaction object for db operation
- post_delete_in_transaction
after creation in transaction
- post_delete
after delete
- pre_state_update_in_transaction
executed before a state update triggerred by a backend event
context.resource contains the resource associated with the update,
context.state contains the state changes,
context.config_version contains the current config version
- post_state_update_in_transaction
as above, but after the state update
- pre_monitoring_update_in_transaction
executed before a monitoring update triggerred by a backend event
context.resource contains the resource associated with the update,
context.monitoring contains the new monitoring information
- post_monitoring_update_in_transaction
as above, but after the monitoring update
- notification
executed when you receive amqp/snmp/cron notification
Testing javascript extensions
-----------------------------
You can test extensions using a testing tool bundled with Gohan with the command
``test_extensions`` (or ``test_ex`` for short). Build and install Gohan, then
run ``gohan test_extensions <paths to files/directories to test>``. The
framework will walk through files and recursively through directories, running
tests in files named ``test_*.js``.
By default, the framework doesn't show logs and results for passing tests, so
you won't see any output if all the tests pass. If you pass a
``-v``/``--verbose`` flag, it will show these messages, and an additional ``All
tests have passed.`` message if all the tests pass.
Test file contents
^^^^^^^^^^^^^^^^^^
Each test file must specify schema and path for preloading extensions:
* var SCHEMA - path to the schema that stores extensions to be tested
* var PATH - path for preloading extensions
Additionally each file can specify:
* one setUp() function that will be called before each test
* one tearDown() function that will be called after each test
* multiple test_<name>() functions that will be called by the framework
* multiple helper functions and variables, with names not starting with prefix
``test_``
Framework API
^^^^^^^^^^^^^
Test framework provides all built in function mentioned in subsection
describing `gohan built in functions`_.
In unit tests, you can use mocks of ``gohan_http``, ``gohan_config`` and
``gohan_db_transaction``. You can pass values that will be returned for given
arguments during subsequent calls by calling
``gohan_*.Expect(argument, ...).Return(value)``. One call to
``gohan_*.Expect(arguments, ...).Return(value)`` provides one response of
``gohan_*`` (FIFO queue). If no return value, or wrong arguments are provided
for a call then an unexpected call is assumed, which will result in test failures.
In addition to the abovementioned functions, the framework provides the
following API:
* ``Fail(format_string, ...)`` - stop execution of a single test case and
return an error
* ``GohanTrigger(event_type, context) : <new context>`` - triggers a specified
type of Gohan event
* ``event_type`` - one of the event types recognized by Gohan (see
event_ subsection)
* ``context`` - context passed to the event handler
* ``MockTransaction(is_new) : <mock transaction>`` - return a mock transaction that
can be used with built-in Gohan methods. Each test is run using a separate
database that is deleted after ``tearDown()``, so there is no need to
clean up the database between tests. Multiple calls to ``MockTransaction()``
within a single ``setUp()``, test, ``tearDown()`` routine when no call to
``CommitMockTransaction()`` has been made will yield the same transaction.
``MockTransaction(true)`` returns forcibly new transaction.
* ``CommitMockTransaction()`` - commit and close the last nonclosed
transaction. After this call any calls to ``MockTransaction()`` return
a new transaction.
* ``MockPolicy() : <mock policy>`` - return a mock policy that
can be used with built-in Gohan methods.
* ``MockAuthorization() : <mock authorization>`` - return a mock authorization that
can be used with built-in Gohan methods.
Example
^^^^^^^
A sample test may look like this:
.. code-block:: javascript
// Schema file containing extensions to be tested
var SCHEMA = "../test_schema.yaml";
/**
* Sample contents of test_schema.yaml:
*
* extensions:
* - id: network
* path: /v2.0/network.*
* url: file://./etc/examples/neutron/network.js
* - id: exceptions
* path: ""
* url: file://./etc/examples/neutron/exceptions.js
* - id: urls
* path: /gohan/v0.1/schema.*
* url: file://./etc/examples/url.js
* schemas:
* - description: Network
* id: network
* parent: ""
* plural: networks
* schema:
* properties:
* id:
* format: uuid
* permission:
* - create
* title: ID
* type: string
* unique: true
* tenant_id:
* format: uuid
* permission:
* - create
* title: Tenant id
* type: string
* unique: false
* propertiesOrder:
* - name
* - id
* - tenant_id
* singular: network
* title: Network
*/
// With the following PATH, "network" and "exceptions" extensions will be loaded
var PATH = "/v2.0/networks";
/**
* Sample contents of network.js:
*
* // filter removes the network with the unwanted id
* gohan_register_handler("post_list", function filter(context) {
* // This call will be mocked, see testNetworkListFilter below
* response = gohan_http("GET", "http://whatisunwanted.com", {}, null);
*
* for (var i = 0; i < context.response.networks.length; i++) {
* if (context.response.networks[i].id == response.unwanted) {
* context.response.networks.splice(i, 1);
* break;
* }
* }
* });
*/
var context;
var network;
function setUp() {
var network_to_create = {
'id': 'new',
'tenant_id': 'azerty'
};
network = gohan_db_create(MockTransaction(), "network", network_to_create);
context = {
'schema': { /* ... */ },
'http_request': { /* ... */ },
'http_response': { /* ... */ },
'path': '/gohan/v0.1/schema',
'response': {
'networks': [
network,
{
'id': 'foo',
'tenant_id': 'xyz'
}
]
}
}
}
function tearDown() {
gohan_db_delete(MockTransaction(), "network", "new");
}
function testNetworkListFilter() {
// First call to gohan_http will return {'unwanted': 'foo'}
gohan_http.Expect("GET", "http://whatisunwanted.com", {}, null).Return({'unwanted': 'foo'});
// Second call to gohan_http will return empty response
gohan_http.Expect("GET", "http://whatisunwanted.com", {}, null).Return({});
// Subsequent calls to gohan_http will fail since they are not expected
var new_context = GohanTrigger('post_list', context);
if (new_context.response.networks.length != 1) {
Fail('Expected 1 network but %d found.', new_context.response.networks.length);
}
if (new_context.response.networks[0].id != network.id) {
Fail('Expected network with id "%s" but "%s" found.', network.id, new_context.response.networks[0].id);
}
}
function testSomethingElse() {
/* ... */
}
Go based extension
-------------------------
You can extend gohan extension by native go.
You can use "go" for code_type and specify your callback id in code.
Also, you can register go struct & call it from javascript.
.. code-block:: yaml
extensions:
- code: exampleapp_callback
code_type: go
id: example
path: .*
- code: exampleapp_callback
code_type: go
id: example
path: .*
- code: |
gohan_register_handler("pre_list", function (context){
var exampleModule = require("exampleapp");
exampleModule.HelloWorld("example app!",
{"hobby": "sleeping"});
});
id: example_js
path: .*
.. code-block:: go
//Register go callback
extension.RegisterGoCallback("exampleapp_callback",
func(event string, context map[string]interface{}) error {
fmt.Printf("callback on %s : %v", event, context)
return nil
})
exampleModule := &ExampleModule{}
//Register go based module for javascript
extension.RegisterModule("exampleapp", exampleModule)
We have exampleapp with comments in exampleapp directory.
You can also, import github.com/cloudwan/server module and
have your own RunServer method to have whole custom route written in go.
Gohan script
-------------------------
Note: This function is experimental. Any APIs are subject to change.
Gohan script is an Ansible-like MACRO language
for extending your Go code with MACRO functionality.
Example
~~~~~~~
.. code-block:: yaml
extensions:
- id: order
path: /v1.0/store/orders
code: |
tasks:
- when: event_type == "post_create_in_transaction"
blocks:
# Try debugger
# - debugger:
- db_get:
tx: $transaction
schema_id: pet
id: $resource.pet_id
register: pet
- when: pet.status != "available"
blocks:
- vars:
exception:
name: CustomException
code: 400
message: "Selected pet isn't available"
else:
- db_update:
tx: $transaction
schema_id: pet
data:
id: $resource.pet_id
status: "pending"
- when: event_type == "post_update_in_transaction"
blocks:
- when: resource.status == "approved"
blocks:
- db_update:
tx: $transaction
schema_id: pet
data:
id: $resource.pet_id
status: "sold"
Standalone Example
~~~~~~~~~~~~~~~~~~~
.. code-block:: yaml
vars:
world: "USA"
foods:
- apple
- orange
- banana
tasks:
- debug: var=$foods[2]
- debug: msg="Hello \" {{ world }}"
- blocks:
- debug: msg="I like {{ item }}"
with_items:
- apple
- orange
- banana
- debug: msg="I like {{ item }}"
with_items: $foods
# Unlike Ansible, We treat a value as identifier if a string value starts with "$"
# otherwise it is a value
- debug: msg="{{ item.key }} likes {{ item.value }}"
with_dict:
Alice: apple
Bob: orange
- debug: msg="This shouldn't be called"
when: 1 == 0
else:
- debug: msg="This should be called"
- fail: "failed"
when: 1 == 1
rescue:
- debug: msg="rescued {{ error }}"
always:
- debug: msg="Drink beer!"
- debug: msg="test {{ 1 == 1 }}"
- include: lib.yaml
vars:
local_vars: hello from imported code
see more detail on extension/gohanscript/test/core_test.yaml
CLI
~~~~~~~
You can run Gohan script code using this
.. code-block:: shell
gohan run ../examples/sample1.yaml
Tasks
~~~~~~~~~
You can run list of tasks.
.. code-block:: yaml
tasks:
- debug: msg="Hello World"
- debug: msg="This is gohan script"
save this file to hello_world.yaml.
.. code-block:: shell
$ gohan run hello_world.yaml
15:17:07.029 ▶ DEBUG hello_world.yaml:1: Hello World
15:17:07.029 ▶ DEBUG hello_world.yaml:2: This is gohan script
Variables
~~~~~~~~~
You can define variables using "vars".
.. code-block:: yaml
tasks:
- vars:
place: "Earth"
person:
name: "John"
age: "30"
- debug: msg="Hello {{place}}"
- debug: var=$place
- debug: msg="Hello {{person.name}} "
- debug: var=$person.name
- debug: # show everything
Any string including "{{" get considered as django template. so
you can use variables in their. if string start with "$", it get considered as
a variable identifier.
(We are using pongo2 which supports subset of django template..)
.. code-block:: shell
$ gohan run variable.yaml
15:21:43.090 ▶ DEBUG variable.yaml:6 Hello Earth
15:21:43.091 ▶ DEBUG variable.yaml:7 Earth
15:21:43.091 ▶ DEBUG variable.yaml:8 Hello John
15:21:43.091 ▶ DEBUG variable.yaml:9 John
15:21:43.091 ▶ DEBUG variable.yaml:10 Dump vars
15:21:43.091 ▶ DEBUG person: map[name:John age:30]
15:21:43.091 ▶ DEBUG __file__: variable.yaml
15:21:43.091 ▶ DEBUG __dir__: .
15:21:43.091 ▶ DEBUG place: Earth
Loops
~~~~~~~~~~~~~~
You can loop over the list item.
.. code-block:: yaml
vars:
foods:
- apple
- orange
- banana
tasks:
- debug: msg="{{ item }}"
with_items:
- apple
- orange
- banana
- debug: msg="{{ item }}"
with_items: $foods
.. code-block:: shell
$ gohan run with_items.yaml
15:28:47.736 ▶ DEBUG with_items.yaml:6 apple
15:28:47.736 ▶ DEBUG with_items.yaml:6 orange
15:28:47.736 ▶ DEBUG with_items.yaml:6 banana
15:28:47.736 ▶ DEBUG with_items.yaml:11 apple
15:28:47.736 ▶ DEBUG with_items.yaml:11 orange
15:28:47.736 ▶ DEBUG with_items.yaml:11 banana
You can also loop over a dict.
.. code-block:: yaml
vars:
person:
name: "John"
age: "30"
tasks:
- debug: msg="{{ item.key }} {{ item.value }}"
with_dict:
name: "John"
age: "30"
- debug: msg="{{ item.key }} {{ item.value }}"
with_dict: $person
.. code-block:: shell
$ gohan run with_items.yaml
15:32:42.513 ▶ DEBUG with_items.yaml:5 name John
15:32:42.513 ▶ DEBUG with_items.yaml:5 age 30
15:32:42.513 ▶ DEBUG with_items.yaml:9 name John
15:32:42.513 ▶ DEBUG with_items.yaml:9 age 30
you can specify loop variable name by specifying loop_var:
.. code-block:: yaml
tasks:
- vars:
result: ""
persons:
- name: Alice
hobbies:
- mailing
- reading
- name: Bob
hobbies:
- mailing
- running
- blocks:
- vars:
result: "{{result}}{{item}}"
with_items: $person.hobbies
with_items: $persons
loop_var: person
Conditional
~~~~~~~~~~~~~~
You can use "when" for conditional.
You can use "else" blocks with "when".
.. code-block:: yaml
vars:
number: 1
tasks:
- debug: msg="Should be called"
when: number == 1
- debug: msg="Should not be called"
when: number == 0
else:
- debug: msg="Should be called"
.. code-block:: shell
$ gohan run when.yaml
15:35:55.358 ▶ DEBUG when.yaml:3 Should be called
Retry
~~~~~~~~~~~~~
You can retry task.
- retry: how many times you will retry a task
- delay: how many seconds you will wait on next retry
.. code-block:: yaml