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 %}