DSL Quest: A WAT Safari - PuppetConf 2013

785 views

Published on

"DSL Quest: A WAT Safari" by Nick Fagerlund, Technical Writer, Puppet Labs.

Presentation Overview: You are standing in an open field, west of a programming language with no specification. ENTER COMMAND. In mid-2012, docs.puppetlabs.com published a completely rewritten reference to the Puppet domain-specific language (DSL). This session is partly the story of how Nick built that, but it's mostly a safari of the weird crap he found along the way, a look at the personality of an undocumented system, a few tips for using Puppet as a calculator, some mission-creep schadenfreude, and maybe the faintest outline of a map for anyone trapped in a maze of twisty passages.

Speaker Bio: Nick Fagerlund was the very first dedicated technical writer at Puppet Labs. Like any responsible pet owner, Puppet Labs has since provided him with companions. Unlike a responsible pet owner, Puppet Labs has fed him after midnight and occasionally splashed water on him. Nick writes (and re-writes) at http://docs.puppetlabs.com, focusing on platform-level components like the Puppet language. He specializes in breaking things and then explaining how they broke. His business card says "weird bugs."

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
785
On SlideShare
0
From Embeds
0
Number of Embeds
337
Actions
Shares
0
Downloads
13
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

DSL Quest: A WAT Safari - PuppetConf 2013

  1. 1. Nick’s DSL Quest: WAT Safari Nick Fagerlund Technical Writer | Puppet Labs @nfagerlund Friday, August 23, 13
  2. 2. puppetconf.com #puppetconf So okay,there I was. Friday, August 23, 13
  3. 3. puppetconf.com #puppetconf When I first got here,we had this “language tutorial.” Friday, August 23, 13
  4. 4. puppetconf.com #puppetconf It was a bit of a mess. (“Additional language features…?”) Friday, August 23, 13
  5. 5. puppetconf.com #puppetconf The Puppet language accreted over time. Friday, August 23, 13
  6. 6. puppetconf.com #puppetconf (And so did the docs.) Friday, August 23, 13
  7. 7. puppetconf.com #puppetconf So I had a good/bad idea. Friday, August 23, 13
  8. 8. puppetconf.com #puppetconf Here’s what I found. Friday, August 23, 13
  9. 9. puppetconf.com #puppetconf $subj  =  {t  =>  'r',  u  =>  'e'} notice(str2bool("$subj")) T to the R Friday, August 23, 13
  10. 10. puppetconf.com #puppetconf $subj  =  {t  =>  'r',  u  =>  'e'} notice(str2bool("$subj")) true T to the R Friday, August 23, 13
  11. 11. puppetconf.com #puppetconf Friday, August 23, 13
  12. 12. puppetconf.com #puppetconf @notify  {'one  tag':    tag  =>  'one', } @notify  {'two  tags':    tag  =>  ['one',  'two'],    #before  =>  Notify['three  tags'] }   @notify  {'three  tags':    tag  =>  ['one',  'two',  'three'],    noop  =>  undef, }   Let’s talk about collectors Friday, August 23, 13
  13. 13. puppetconf.com #puppetconf Notify  <|  tag  ==  'one'  |> Notice:  Compiled  catalog  for  magpie.lan  in  environment   production  in  0.11  seconds Notice:  one  tag Notice:  /Stage[main]//Notify[one  tag]/message:  defined   'message'  as  'one  tag' Notice:  three  tags Notice:  /Stage[main]//Notify[three  tags]/message:  defined   'message'  as  'three  tags' Notice:  two  tags Notice:  /Stage[main]//Notify[two  tags]/message:  defined   'message'  as  'two  tags' Let’s talk about collectors Friday, August 23, 13
  14. 14. puppetconf.com #puppetconf Notify  <|  'one'  ==  tag  |> Error:  Could  not  parse  for  environment  production:  Syntax   error  at  'one';  expected  '|>'  at  /Users/nick/Documents/ manifests/collector-­‐search.pp:29  on  node  magpie.lan Let’s talk about collectors Friday, August 23, 13
  15. 15. puppetconf.com #puppetconf Notify  <|  tag  ==  ['one',  'two']  |> Notice:  Compiled  catalog  for  magpie.lan  in  environment   production  in  0.09  seconds Notice:  one  tag Notice:  /Stage[main]//Notify[one  tag]/message:  defined   'message'  as  'one  tag' Notice:  three  tags Notice:  /Stage[main]//Notify[three  tags]/message:  defined   'message'  as  'three  tags' Notice:  two  tags Notice:  /Stage[main]//Notify[two  tags]/message:  defined   'message'  as  'two  tags' Notice:  Finished  catalog  run  in  0.17  seconds Let’s talk about collectors Friday, August 23, 13
  16. 16. puppetconf.com #puppetconf Notify  <|  tag  !=  ['one',  'two']  |> Notice:  Compiled  catalog  for  magpie.lan  in  environment   production  in  0.09  seconds Notice:  three  tags Notice:  /Stage[main]//Notify[three  tags]/message:  defined   'message'  as  'three  tags' Notice:  two  tags Notice:  /Stage[main]//Notify[two  tags]/message:  defined   'message'  as  'two  tags' Notice:  Finished  catalog  run  in  0.18  seconds Let’s talk about collectors Friday, August 23, 13
  17. 17. puppetconf.com #puppetconf CONCLUSION: “==” != “==” Friday, August 23, 13
  18. 18. puppetconf.com #puppetconf Friday, August 23, 13
  19. 19. puppetconf.com #puppetconf class  class  {    notify  {'hey  it  worked':} } include  class Results Classy Friday, August 23, 13
  20. 20. puppetconf.com #puppetconf class  class  {    notify  {'hey  it  worked':} } include  class Error:  Could  not  parse  for  environment   production:  Syntax  error  at  'class'  at  / Users/nick/Documents/manifests/ class_class.pp:6  on  node  magpie.lan Classy Friday, August 23, 13
  21. 21. puppetconf.com #puppetconf class  class  {    notify  {'hey  it  worked':} } include  "class" Classy Friday, August 23, 13
  22. 22. puppetconf.com #puppetconf class  class  {    notify  {'hey  it  worked':} } include  "class" Notice:  Compiled  catalog  for  magpie.lan  in  environment   production  in  0.09  seconds Notice:  hey  it  worked Notice:  /Stage[main]/Class/Notify[hey  it  worked]/message:   defined  'message'  as  'hey  it  worked' Notice:  Finished  catalog  run  in  0.19  seconds Classy Friday, August 23, 13
  23. 23. puppetconf.com #puppetconf class  parent  {        define  doessomething  {  notice("parentvar  is  set,  in  the                   parent::doessomething  define")  }        class  whoa  {  notice("Okay  that  works  w/  classes  too")  }        $otherparentvar  =  "haha  whoa" } search('parent') doessomething{'something':} include  whoa notice($otherparentvar)  #  This  one  doesn't  work  though,  because   it  attaches  the  NAMESPACE,  not  the  scope. Search??? Friday, August 23, 13
  24. 24. puppetconf.com #puppetconf class  parent  {        define  doessomething  {  notice("parentvar  is  set,  in  the                   parent::doessomething  define")  }        class  whoa  {  notice("Okay  that  works  w/  classes  too")  }        $otherparentvar  =  "haha  whoa" } search('parent') doessomething{'something':} include  whoa notice($otherparentvar)  #  This  one  doesn't  work  though,  because   it  attaches  the  NAMESPACE,  not  the  scope. It  dumps  a  random  namespace  into  the  local   namespace??? Search??? Friday, August 23, 13
  25. 25. puppetconf.com #puppetconf (This is still in Puppet 3.2.) (photo via http:// weheartit.com/entry/ 68358166) Friday, August 23, 13
  26. 26. puppetconf.com #puppetconf [  Notify['first'],  Notify['second']  ] It’s  an  array  of  resource  references,  right? Have you seen this syntax? Friday, August 23, 13
  27. 27. puppetconf.com #puppetconf Notify[  'first',  'second'  ] ??? How about this one? Friday, August 23, 13
  28. 28. puppetconf.com #puppetconf Notify[  ['first',  'second']  ] (Okay,  it  ends  up  being  the  same  as  the  last  one  for  some   reason.) How about this one? Friday, August 23, 13
  29. 29. puppetconf.com #puppetconf #  OK require  =>  Notify['first',  'second'] require  =>  [  Notify['first'],  Notify['second']  ] Notify['first',  'second']  -­‐>  Notify['third'] #  BAD [  Notify['first'],  Notify['second']  ]  -­‐>   Notify['third'] ?????!! They all look kind of similar? Friday, August 23, 13
  30. 30. puppetconf.com #puppetconf #  OK Notify['first',  'second']  {    message  =>  'Adding  a  message  to  these.' } #  BAD [  Notify['first'],  Notify['second']  ]  {    message  =>  'Adding  a  message  to  these.' } ?????!! They all look kind of similar? Friday, August 23, 13
  31. 31. puppetconf.com #puppetconf So,these are two completely different syntaxes. (I named the non-array one “multi- references.) Friday, August 23, 13
  32. 32. puppetconf.com #puppetconf class  bar  {    notice("From  class  bar") } class  foo::bar  {    notice("From  class  foo::bar") } class  foo  {    include  bar } include  foo Include bar... but only as a last resort Friday, August 23, 13
  33. 33. puppetconf.com #puppetconf class  bar  {    notice("From  class  bar") } class  foo::bar  {    notice("From  class  foo::bar") } class  foo  {    include  bar } include  foo Notice:  Scope(Class[Foo::Bar]):  From  class  foo::bar (this  is  bug  #2053.) Include bar... but only as a last resort Friday, August 23, 13
  34. 34. puppetconf.com #puppetconf #  Is  the  ==  operator  case-­‐sensitive?  NO notice(  'eat'  ==  'EAt'  ) #  Is  the  'in'  operator  case-­‐sensitive?  YES notice(  'eat'  in  'EAten'  ) Notice:  Scope(Class[main]):  true Notice:  Scope(Class[main]):  false Case sensitivity training Friday, August 23, 13
  35. 35. puppetconf.com #puppetconf ANYWAY Friday, August 23, 13
  36. 36. puppetconf.com #puppetconf #  The  $is_virtual  fact  is  false  on  this  machine if  $is_virtual  {    notice("Guess  this  is  a  virtual  machine!") } Falseness is truth Friday, August 23, 13
  37. 37. puppetconf.com #puppetconf #  The  $is_virtual  fact  is  false  on  this  machine if  $is_virtual  {    notice("Guess  this  is  a  virtual  machine!") } Notice:  Scope(Class[main]):  Guess  this  is  a  virtual   machine! Falseness is truth Friday, August 23, 13
  38. 38. puppetconf.com #puppetconf (Use the str2bool() function from puppetlabs/stdlib) Friday, August 23, 13
  39. 39. puppetconf.com #puppetconf This,of course,escalated quickly. Friday, August 23, 13
  40. 40. puppetconf.com #puppetconf Code Results What IS truth,anyway? Friday, August 23, 13
  41. 41. puppetconf.com #puppetconf $x  =  5 $y  =  3 notice("Value  of  x  is  ${x}") You’ve  seen  this  before. Express yourself Friday, August 23, 13
  42. 42. puppetconf.com #puppetconf $x  =  5 $y  =  3 notice("Five  by  three  is  ${$x  *  $y}") Express yourself Friday, August 23, 13
  43. 43. puppetconf.com #puppetconf $x  =  5 $y  =  3 notice("Five  by  three  is  ${$x  *  $y}") Notice:  Scope(Class[main]):  Five  by  three  is  15 Express yourself Friday, August 23, 13
  44. 44. puppetconf.com #puppetconf $mystring  =  "Nothing  in  particular" notice("But  it  was  ${$mystring  =~  /thing/}") Notice:  Scope(Class[main]):  But  it  was  true Express yourself Whoa Friday, August 23, 13
  45. 45. puppetconf.com #puppetconf notice("This  time  with  an  in  statement:  Is  there   a  thing  in  nothing?  ${"thing"  in  $mystring}  so   yeah") Notice:  Scope(Class[main]):  This  time  with  an  in   statement:  Is  there  a  thing  in  nothing?  true  so  yeah Express yourself Friday, August 23, 13
  46. 46. puppetconf.com #puppetconf notice("There's  a  function  operand  in  here:                      ${  fqdn_rand(30)  +  '90'  }  so  yeah") WELL,  at  least  THAT  one  doesn’t  work. Express yourself Friday, August 23, 13
  47. 47. puppetconf.com #puppetconf notice("Variable  with  doubled  sigil:  ${  $x}  so   yeah") notice("Singular  sigil,  but  with  wacky  spacing:   ${    x}  so  yeah") Notice:  Scope(Class[main]):  Variable  with  doubled  sigil:   5  so  yeah Notice:  Scope(Class[main]):  Singular  sigil,  but  with   wacky  spacing:  5  so  yeah Express yourself Friday, August 23, 13
  48. 48. puppetconf.com #puppetconf notice("Yo  dawg,  I  heard  you  like  ${"strings,  so   I  put  a  string  in  your"}  string") Sorry  for  partying  like  it’s  200X,  but  anyway  yeah,  that   totally  works. Express yourself Friday, August 23, 13
  49. 49. puppetconf.com #puppetconf #  What  about  this?   notice("Twenty  by  eighty  is  ${  20  *  80  }  so   yeah") Error:  left  operand  of  *  is  not  a  number Express yourself Friday, August 23, 13
  50. 50. puppetconf.com #puppetconf notice("Twenty  by  eighty  is  ${  '20'  *  '80'  }  so   yeah") Notice:  Scope(Class[main]):  Twenty  by  eighty  is  1600  so   yeah Express yourself Friday, August 23, 13
  51. 51. puppetconf.com #puppetconf And at this point I was like Friday, August 23, 13
  52. 52. puppetconf.com #puppetconf (It turns out the first bareword in an interpolation block gets silently turned into a variable,so 20 became $20,which would be a regex capture variable except we weren’t inside a conditional so it was undef???) Friday, August 23, 13
  53. 53. puppetconf.com #puppetconf So then I was like Friday, August 23, 13
  54. 54. puppetconf.com #puppetconf Friday, August 23, 13
  55. 55. puppetconf.com #puppetconf yeah Friday, August 23, 13
  56. 56. puppetconf.com #puppetconf file  {'file1':    path  =>  '/tmp/file1',    ensure  =>  file,    alias  =>  ['othername',  'fourthname'], } file  {'file2':    path  =>  '/tmp/file2',    ensure  =>  file,    before  =>  File['othername'], } Let’s talk about aliases Friday, August 23, 13
  57. 57. puppetconf.com #puppetconf file  {'file1':    path  =>  '/tmp/file1',    ensure  =>  file,    alias  =>  ['othername',  'fourthname'], } file  {'file2':    path  =>  '/tmp/file2',    ensure  =>  file,    before  =>  File['othername'], } This  works  fine. Let’s talk about aliases Friday, August 23, 13
  58. 58. puppetconf.com #puppetconf file  {'file1':    alias  =>  ['othername',  'fourthname'], } file  {'file2':} File['file2']  -­‐>  File['othername'] Error:  Could  not  find  resource  'File[othername]'  for   relationship  from  'File[file2]'  on  node  magpie.lan So  it  works  in  metaparameters,  but  not  in  chaining   statements.   Okay! Let’s talk about aliases Friday, August 23, 13
  59. 59. puppetconf.com #puppetconf @file  {'file1':    path  =>  '/tmp/file1',    ensure  =>  file,    alias  =>  ['othername',  'fourthname'], } realize  File['othername'] Nope! Let’s talk about aliases Friday, August 23, 13
  60. 60. puppetconf.com #puppetconf @file  {'file1':    path  =>  '/tmp/file1',    ensure  =>  file,    alias  =>  ['othername',  'fourthname'], } realize  File['/tmp/file1'] Nope! Let’s talk about aliases Friday, August 23, 13
  61. 61. puppetconf.com #puppetconf @file  {'file1':    path  =>  '/tmp/file1',    ensure  =>  file,    alias  =>  ['othername',  'fourthname'], } File  <|  alias  ==  'fourthname'  |> PURRS  LIKE  A  KITTEN! Let’s talk about aliases Friday, August 23, 13
  62. 62. puppetconf.com #puppetconf Anyway,what did I learn? (In the larger sense,not in the str2bool({t => ‘r’,u => ‘e’}) sense.) Friday, August 23, 13
  63. 63. puppetconf.com #puppetconf Do science to it. Friday, August 23, 13
  64. 64. puppetconf.com #puppetconf Long-lived systems get weird. Friday, August 23, 13
  65. 65. puppetconf.com #puppetconf Talk to the old-timers. Friday, August 23, 13
  66. 66. puppetconf.com #puppetconf WAT brings us together! Friday, August 23, 13
  67. 67. puppetconf.com #puppetconf (Pause here for general theory of the social capital of WAT in engineering cultures.) Friday, August 23, 13
  68. 68. puppetconf.com #puppetconf And venting about WAT can keep your morale up. Because c’mon. That’s pretty funny. Friday, August 23, 13
  69. 69. puppetconf.com #puppetconf https:// github.com/ nfagerlund/ evil-made- manifest (photo via http:// taterpie.tumblr.com/ post/56826040138/ thats-an-awesome- shot) Friday, August 23, 13
  70. 70. Thank You Nick Fagerlund Technical Writer | Puppet Labs @nfagerlund Collaborate. Automate. Ship. Friday, August 23, 13
  71. 71. Follow us on Twitter @puppetlabs youtube.com/puppetlabsinc slideshare.net/puppetlabs Collaborate. Automate. Ship. Friday, August 23, 13

×