github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/docs/gohan_extension.md (about)

     1  ## Gohan script extension
     2  {% raw %}
     3  
     4  Note: This function is experimental. Any APIs are subject to change.
     5  
     6  Gohan script is an Ansible-like MACRO language
     7  for extending your Go code with MACRO functionality.
     8  
     9  ## Example
    10  
    11  ```
    12  extensions:
    13  - id: order
    14    path: /v1.0/store/orders
    15    code: |
    16      tasks:
    17      - when: event_type == "post_create_in_transaction"
    18        blocks:
    19        #  Try debugger
    20        # - debugger:
    21        - db_get:
    22            tx: $transaction
    23            schema_id: pet
    24            id: $resource.pet_id
    25          register: pet
    26        - when: pet.status != "available"
    27          blocks:
    28          - vars:
    29              exception:
    30                name: CustomException
    31                code: 400
    32                message: "Selected pet isn't available"
    33          else:
    34          - db_update:
    35              tx: $transaction
    36              schema_id: pet
    37              data:
    38                  id: $resource.pet_id
    39                  status: "pending"
    40      - when: event_type == "post_update_in_transaction"
    41        blocks:
    42        - when: resource.status == "approved"
    43          blocks:
    44          - db_update:
    45              tx: $transaction
    46              schema_id: pet
    47              data:
    48                id: $resource.pet_id
    49                status: "sold"
    50  ```
    51  
    52  ## Standalone Example
    53  
    54  ```
    55      vars:
    56        world: "USA"
    57        foods:
    58        - apple
    59        - orange
    60        - banana
    61      tasks:
    62      - debug: var=$foods[2]
    63      - debug: msg="Hello \" {{ world }}"
    64      - blocks:
    65          - debug: msg="I like {{ item }}"
    66            with_items:
    67          - apple
    68          - orange
    69          - banana
    70          - debug: msg="I like {{ item }}"
    71            with_items: $foods
    72          # Unlike Ansible, We treat a value as identifier if a string value starts with "$"
    73          # otherwise it is a value
    74          - debug: msg="{{ item.key }} likes {{ item.value }}"
    75            with_dict:
    76              Alice: apple
    77              Bob: orange
    78          - debug: msg="This shouldn't be called"
    79            when: 1 == 0
    80            else:
    81            - debug: msg="This should be called"
    82          - fail: "failed"
    83            when: 1 == 1
    84            rescue:
    85            - debug: msg="rescued {{ error }}"
    86            always:
    87            - debug: msg="Drink beer!"
    88      - debug: msg="test {{ 1 == 1 }}"
    89      - include: lib.yaml
    90          vars:
    91          local_vars: hello from imported code
    92  ```
    93  
    94  see more detail on extension/gohanscript/test/core_test.yaml
    95  
    96  ## CLI
    97  
    98  You can run Gohan script code using this
    99  
   100  ```
   101  gohan run ../examples/sample1.yaml
   102  ```
   103  
   104  ## Tasks
   105  
   106  You can run list of tasks.
   107  
   108  ```
   109    tasks:
   110    - debug: msg="Hello World"
   111    - debug: msg="This is gohan script"
   112  ```
   113  
   114  save this file to hello_world.yaml.
   115  
   116  ```
   117  $ gohan run hello_world.yaml
   118  15:17:07.029 ▶ DEBUG  hello_world.yaml:1: Hello World
   119  15:17:07.029 ▶ DEBUG  hello_world.yaml:2: This is gohan script
   120  ```
   121  
   122  ## Variables
   123  
   124  You can define variables using "vars".
   125  
   126  ```
   127    tasks:
   128    - vars:
   129        place: "Earth"
   130        person:
   131          name: "John"
   132          age: "30"
   133    - debug: msg="Hello {{place}}"
   134    - debug: var=$place
   135    - debug: msg="Hello {{person.name}} "
   136    - debug: var=$person.name
   137    - debug: # show everything
   138  ```
   139  
   140  Any string including "{{" get considered as django template. so
   141  you can use variables in their. if string start with $, it get considered as
   142  a variable identifier.
   143  (We are using pongo2 which supports subset of django template..)
   144  
   145  ```
   146      $ gohan run variable.yaml
   147      15:21:43.090 ▶ DEBUG  variable.yaml:6 Hello Earth
   148      15:21:43.091 ▶ DEBUG  variable.yaml:7 Earth
   149      15:21:43.091 ▶ DEBUG  variable.yaml:8 Hello John
   150      15:21:43.091 ▶ DEBUG  variable.yaml:9 John
   151      15:21:43.091 ▶ DEBUG  variable.yaml:10 Dump vars
   152      15:21:43.091 ▶ DEBUG      person: map[name:John age:30]
   153      15:21:43.091 ▶ DEBUG      __file__: variable.yaml
   154      15:21:43.091 ▶ DEBUG      __dir__: .
   155      15:21:43.091 ▶ DEBUG      place: Earth
   156  ```
   157  
   158  ## Loops
   159  
   160  You can loop over the list item.
   161  
   162  ```
   163      vars:
   164          foods:
   165          - apple
   166          - orange
   167          - banana
   168      tasks:
   169      - debug: msg="{{ item }}"
   170        with_items:
   171        - apple
   172        - orange
   173        - banana
   174      - debug: msg="{{ item }}"
   175        with_items: $foods
   176  ```
   177  
   178  ```
   179      $ gohan run with_items.yaml
   180      15:28:47.736 ▶ DEBUG  with_items.yaml:6 apple
   181      15:28:47.736 ▶ DEBUG  with_items.yaml:6 orange
   182      15:28:47.736 ▶ DEBUG  with_items.yaml:6 banana
   183      15:28:47.736 ▶ DEBUG  with_items.yaml:11 apple
   184      15:28:47.736 ▶ DEBUG  with_items.yaml:11 orange
   185      15:28:47.736 ▶ DEBUG  with_items.yaml:11 banana
   186  ```
   187  
   188  You can also loop over a dict.
   189  
   190  ```
   191      vars:
   192      person:
   193          name: "John"
   194          age: "30"
   195      tasks:
   196      - debug: msg="{{ item.key }} {{ item.value }}"
   197        with_dict:
   198          name: "John"
   199          age: "30"
   200      - debug: msg="{{ item.key }} {{ item.value }}"
   201        with_dict: $person
   202  ```
   203  
   204  ```
   205      $ gohan run with_items.yaml
   206      15:32:42.513 ▶ DEBUG  with_items.yaml:5 name John
   207      15:32:42.513 ▶ DEBUG  with_items.yaml:5 age 30
   208      15:32:42.513 ▶ DEBUG  with_items.yaml:9 name John
   209      15:32:42.513 ▶ DEBUG  with_items.yaml:9 age 30
   210  ```
   211  
   212  ```
   213      tasks:
   214      - vars:
   215          result: ""
   216          persons:
   217          - name: Alice
   218            hobbies:
   219            - mailing
   220            - reading
   221          - name: Bob
   222            hobbies:
   223            - mailing
   224            - running
   225      - blocks:
   226          - vars:
   227              result: "{{result}}{{item}}"
   228            with_items: $person.hobbies
   229        with_items: $persons
   230        loop_var: person
   231  ```
   232  
   233  ## Conditional
   234  
   235  You can use "when" for conditional.
   236  You can use "else" blocks with "when".
   237  
   238  ```
   239      vars:
   240        number: 1
   241      tasks:
   242      - debug: msg="Should be called"
   243        when: number == 1
   244      - debug: msg="Should not be called"
   245        when: number == 0
   246        else:
   247        - debug: msg="Should be called"
   248  ```
   249  
   250  ```
   251      $ gohan run when.yaml
   252      15:35:55.358 ▶ DEBUG  when.yaml:3 Should be called
   253  ```
   254  
   255  ## Retry
   256  
   257  You can retry task.
   258  
   259  - retry: how many times you will retry a task
   260  - delay: how many seconds you will wait on next retry
   261  
   262  ```
   263      tasks:
   264      - fail: msg="Failed"
   265        retry: 3
   266        delay: 3
   267  ```
   268  
   269  ```
   270      $ gohan run retry.yaml
   271      15:43:35.720 ▶ WARNING  error: tasks[0]: Failed
   272      15:43:35.720 ▶ WARNING  error: tasks[0]: Failed
   273      Failed
   274  ```
   275  
   276  ## Blocks
   277  
   278  You can group a set of tasks using blocks.
   279  blocks also supports loops, conditional and retries.
   280  
   281  ```
   282      tasks:
   283      - blocks:
   284        - debug: msg="hello"
   285        - debug: msg="from in block"
   286  ```
   287  
   288  ```
   289      $ gohan run blocks.yaml
   290      15:48:30.231 ▶ DEBUG  blocks.yaml:2 hello
   291      15:48:30.231 ▶ DEBUG  blocks.yaml:3 from in block
   292  ```
   293  
   294  ## Register
   295  
   296  You can change variable value using "register".
   297  
   298  ```
   299      tasks:
   300      - http_get: url=https://status.github.com/api/status.json
   301        register: result
   302      - debug: msg="{{result.contents.status}}"
   303  ```
   304  
   305  ```
   306      $ gohan run register.yaml
   307      15:51:11.005 ▶ DEBUG  [register.yaml line:3 column:2] good
   308  ```
   309  
   310  ## Concurrency
   311  
   312  We support concurrent execution over a loop.
   313  
   314  - worker: specify number of max workers
   315  
   316  ```
   317      tasks:
   318      - blocks:
   319        - http_get: url="https://status.github.com/{{ item }}"
   320          register: result
   321        - debug: var=$result.raw_body
   322      worker: 3
   323      with_items:
   324      - /api/status.json
   325      - /api.json
   326      - /api/last-message.json
   327  ```
   328  
   329  ```
   330      $ gohan run worker.yaml
   331      15:58:49.151 ▶ DEBUG  worker.yaml:4 {"status_url":"https://status.github.com/api/status.json","messages_url":"https://status.github.com/api/messages.json","last_message_url":"https://status.github.com/api/last-message.json","daily_summary":"https://status.github.com/api/daily-summary.json"}
   332      15:58:49.156 ▶ DEBUG  worker.yaml:4 {"status":"good","body":"Everything operating normally.","created_on":"2016-03-03T22:03:59Z"}
   333      15:58:49.156 ▶ DEBUG  worker.yaml:4 {"status":"good","last_updated":"2016-03-08T23:58:27Z"}
   334  ```
   335  
   336  You can also execute tasks in background.
   337  
   338  ```
   339      tasks:
   340      - background:
   341        - sleep: 1000
   342        - debug: msg="called 2"
   343      - debug: msg="called 1"
   344      - sleep: 2000
   345      - debug: msg="called 3"
   346  ```
   347  
   348  ```
   349      $ gohan run background.yaml
   350      16:02:55.034 ▶ DEBUG  background.yaml:6 called 1
   351      16:02:56.038 ▶ DEBUG  background.yaml:4 called 2
   352      16:02:57.038 ▶ DEBUG  background.yaml:8 called 3
   353  ```
   354  
   355  
   356  ### Define function
   357  
   358  You can define function using "define" task.
   359  
   360  - name: name of function
   361  - args: arguments
   362  - body: body of code
   363  
   364  ```
   365      tasks:
   366      - define:
   367          name: fib
   368          args:
   369            x: int
   370          body:
   371          - when: x < 2
   372            return: x
   373          - sub_int: a=$x b=1
   374            register: $x
   375          - fib:
   376              x: $x
   377            register: a
   378          - sub_int: a=$x b=1
   379            register: x
   380          - fib:
   381              x: $x
   382            register: b
   383          - add_int: a=$a b=$b
   384            register: result
   385          - return: result
   386      - fib: x=10
   387        register: result2
   388      - debug: msg="result = {{result2}}"
   389  ```
   390  
   391  you can use return task in function block.
   392  
   393  ```
   394      $ gohan run fib.yaml
   395      16:07:39.964 ▶ DEBUG  fib.yaml:23 result = 55
   396  ```
   397  
   398  ### Include
   399  
   400  You can include gohan script
   401  
   402  ```
   403      tasks:
   404      - include: lib.yaml
   405  ```
   406  
   407  ```
   408      $ gohan run include.yaml
   409      16:11:20.569 ▶ DEBUG  lib.yaml:0 imported
   410  ```
   411  
   412  ## Debugger mode
   413  
   414  You can set breakpoint using "debugger"
   415  
   416  ```
   417      vars:
   418      world: "USA"
   419      foods:
   420      - apple
   421      - orange
   422      - banana
   423      tasks:
   424      - debugger:
   425      - debug: msg="Hello {{ world }}"
   426  ```
   427  
   428  ```
   429      10:50:55.052 gohanscript INFO  Debugger port: telnet localhost 40000
   430  ```
   431  
   432  
   433  Supported command in debugger mode:
   434  
   435  - s: step task
   436  - n: next task
   437  - r: return
   438  - c: continue
   439  - p: print current context
   440  - p code: execute miniGo
   441  - l: show current task
   442  
   443  You will get separate port per go routine.
   444  
   445  ## Command line argument
   446  
   447  additional arguments will be stored in variable.
   448  If the value doesn't contain "=", it will be pushed to args.
   449  If the value contains "=", it get splitted for key and value and stored in flags.
   450  
   451  ```
   452      tasks:
   453      - debug: msg="{{ flags.greeting }} {{ args.0 }}"
   454  ```
   455  
   456  ```
   457  $ gohan run args.yaml world greeting=hello
   458  hello world
   459  ```
   460  
   461  ## Run test
   462  
   463  You can run gohan build-in test. gohan test code find test gohan code
   464  in the specified directory.
   465  
   466  ```
   467      gohan test
   468  ```
   469  
   470  
   471  ## Run Gohan script from Go
   472  
   473  ```
   474  	vm := gohan.NewVM()
   475  	_, err := vm.RunFile("test/spec.yaml")
   476  	if err != nil {
   477  		t.Error(err)
   478  	}
   479  ```
   480  
   481  ## Add new task using Go
   482  
   483  You can auto generate adapter functions using ./extension/gohanscript/tools/gen.go.
   484  
   485  ```
   486    go run ./extension/gohanscript/tools/gen.go genlib -t extension/gohanscript/templates/lib.tmpl -p github.com/cloudwan/gohan/extension/gohanscript/lib -e autogen -ep extension/gohanscript/autogen
   487  ```
   488  
   489  
   490  ## More examples and supported functions
   491  
   492  please take a look
   493  
   494  - extension/gohanscript/lib/tests
   495  - extension/gohanscript/tests
   496  
   497  {% endraw %}