{"id":1752,"date":"2017-09-15T15:14:50","date_gmt":"2017-09-15T13:14:50","guid":{"rendered":"http:\/\/miroslaw.borodziuk.eu\/?p=1752"},"modified":"2020-02-13T23:31:19","modified_gmt":"2020-02-13T22:31:19","slug":"puppet","status":"publish","type":"post","link":"http:\/\/miro.borodziuk.eu\/index.php\/2017\/09\/15\/puppet\/","title":{"rendered":"J\u0119zyk DSL Puppeta cz.2"},"content":{"rendered":"<p>Dalsza cz\u0119\u015b\u0107 kursu traktuj\u0105cego o najpopularniejszym narz\u0119dziu o zarz\u0105dzania konfiguracj\u0105 infrastruktury.<\/p>\n<p><!--more--><\/p>\n<p><span style=\"color: #3366ff;\">Git.<\/span><\/p>\n<p>Aby nasz <em>Puppet<\/em> m\u00f3g\u0142 wsp\u00f3\u0142pracowa\u0107 z Gitem potrzebujemy mie\u0107 tam za\u0142o\u017cone w pierwszej kolejno\u015bci konto. Po za\u0142o\u017ceniu konta generujemy klucz ssh, kt\u00f3ry p\u00f3\u017aniej wgramy na Gita.<\/p>\n<pre class=\"lang:sh decode:true\"># ssh-keygen -t rsa -b 4096 -C \"name@example.com\"<\/pre>\n<p>Wy\u015bwietlamy wygenerowany klucz publiczny.<\/p>\n<pre class=\"lang:sh decode:true\"># cat \/root\/.ssh\/id_rsa.pub\r\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDHVMyMyR66Sf4UI0xU3bHStMujeGWIKUMxxgOWd8o+rRu0\/tvkf2E6AB0blYbKHNwU469rqvUs\/mJTWmZYLB45Do52ODUFR25Ypa6039BE3g96OKntdTMwzkj4qhUJMC1GG50VSicsE6BNj9qGWDPmCl1Ri+tg+laBjpYZL2JTVXKAmun7eMtKyO1FarMMsJvvBLqVa3annOxUKMQSYJVolr6YvFQOjcqgK4Ivv4QF7J4D\/4Y+Sb3wtb\/qjHCN5XAZpcdPeTyyjY6nfpQmvWBWZxsn+BgK9luugf8igXR+1+oF6lzTUub1aVEbPdUau\/n+WHjZDJ1k7Eyrc9aFk9PiC5IeUKnbjfgwt5hxurVxc4Sf2iwjTuY7am2z8qNKUrTtOSuL4h5wtTrwj55m91Kgg\/axgodbsh0UZmDoq99vBFOgtQxMlrf3G+vNPzLaNJRFqNzfiqUmiwO301lA0+i8aCMSyfKjtNBzejiJ5vNy33Jh6QbuLvMV2AFeRZcVCfB9T8MYn194ModE2eHH6jEaa3hypW4rPwKPKhPbONjL+RYLFUU5AxO7YStH3U20A7\/GkcNK6WQ3X00xy1asiME0\/AV5S4MOl\/z471I8YYneBoMqJ48BvfPe7xFB2Ay2uEqLUbT4FzVXkElG\/mEXqE2WotSHbqSWgtPsav2r\/EH33Q== name@example.com<\/pre>\n<p>A nast\u0119pnie wklejamy go na Git hubie (www.github.com) w sekcji<\/p>\n<p><em>Settings -&gt; SSH and GPG keys -&gt; New SSH key<\/em>.<\/p>\n<p>Tworzymy tak\u017ce nasze repozytorium o nazwie np.<em> puppet-nginx<\/em>.<\/p>\n<p><em>\u00a0Settings -&gt; Repositories -&gt; + -&gt; New repository -&gt; Repository name<\/em><\/p>\n<p>Na naszej maszynie instalujemy gita.<\/p>\n<pre class=\"lang:sh decode:true\">yum -y install git<\/pre>\n<p>Testujemy nasze repozytorium.<\/p>\n<pre class=\"lang:sh decode:true\"># cd \/tmp\r\n# git clone git@github.com:GIT_ACCOUNT_NAME\/puppet-nginx.git<\/pre>\n<p>Gdzie <em>GIT_ACCOUNT_NAME<\/em> to nazwa naszego konta na githubie, a <em>puppet-ssh<\/em> to to nazwa repozytorium.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Modu\u0142y.<\/span><\/p>\n<p>Aby manifest by\u0142 bardziej czytelny i \u0142atwiejszy w utrzymaniu dobrym zwyczajem jest rozbicie go na modu\u0142y.<\/p>\n<p>Generowanie modu\u0142u:<\/p>\n<pre class=\"lang:sh decode:true\"># puppet module generate &lt;MAINTAINER&gt;-&lt;MODULE_NAME&gt;<\/pre>\n<p>Nazwa modu\u0142u powinna:<\/p>\n<ul>\n<li>zawiera\u0107 male litery,<\/li>\n<li>zawiera\u0107 liczby,<\/li>\n<li>zawiera\u0107 podkre\u015blenia &#8220;_&#8221;,<\/li>\n<li>zaczyna\u0107 si\u0119 od ma\u0142ej litery,<\/li>\n<li>nie mo\u017ce zawiera\u0107 dwukropek &#8220;::&#8221;.<\/li>\n<\/ul>\n<p>Wej\u015bcie do katalogu z modu\u0142ami:<\/p>\n<pre class=\"lang:sh decode:true\"># cd \/etc\/puppetlabs\/code\/environments\/production\/modules<\/pre>\n<p>Wy\u015bwietlenie aktualnie zainstalowanych modu\u0142\u00f3w:<\/p>\n<pre class=\"lang:sh decode:true \"># ls\r\napache concat ntp stdlib<\/pre>\n<p>Wygenerowanie naszego modu\u0142u o nazwie np. ssh (zamiast <em>username<\/em> wpisujemy nazw\u0119 u\u017cytownika):<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppmaster modules]# puppet module generate username-nginx\r\nWe need to create a metadata.json file for this module. Please answer the\r\nfollowing questions; if the question is not applicable to this module, feel free\r\nto leave it blank.\r\n\r\nPuppet uses Semantic Versioning (semver.org) to version modules.\r\nWhat version is this module? [0.1.0]\r\n--&gt;\r\n\r\nWho wrote this module? [username]\r\n--&gt; My Name &lt;email@address.com&gt;\r\n\r\nWhat license does this module code fall under? [Apache-2.0]\r\n--&gt;\r\n\r\nHow would you describe this module in a single sentence?\r\n--&gt; Module is associated with NGINX.\r\n\r\nWhere is this module's source code repository?\r\n--&gt; https:\/\/github.com\/<em>GIT_ACCOUNT_NAME<\/em>\/puppet-nginx\r\n\r\nWhere can others go to learn more about this module? [https:\/\/github.com\/mborodziuk\/pupp et-ssh]\r\n--&gt;\r\n\r\nWhere can others go to file issues about this module? [https:\/\/github.com\/mborodziuk\/pup pet-ssh\/issues]\r\n--&gt;\r\n\r\n----------------------------------------\r\n{\r\n\"name\": \"username-nginx\",\r\n\"version\": \"0.1.0\",\r\n\"author\": \"My Name &lt;email@address.com&gt;\",\r\n\"summary\": \"Module is associated with NGINX.\",\r\n\"license\": \"Apache-2.0\",\r\n\"source\": \"https:\/\/github.com\/<em>GIT_ACCOUNT_NAME<\/em>\/puppet-nginx\",\r\n\"project_page\": \"https:\/\/github.com\/<em>GIT_ACCOUNT_NAME<\/em>\/puppet-nginx\",\r\n\"issues_url\": \"https:\/\/github.com\/<em>GIT_ACCOUNT_NAME<\/em>\/puppet-nginx\/issues\",\r\n\"dependencies\": [\r\n{\"name\":\"puppetlabs-stdlib\",\"version_requirement\":\"&gt;= 1.0.0\"}\r\n],\r\n\"data_provider\": null\r\n}\r\n----------------------------------------\r\n\r\nAbout to generate this metadata; continue? [n\/Y]\r\n--&gt; Y\r\n\r\nNotice: Generating module at \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx...\r\nNotice: Populating templates...\r\nFinished; module generated in nginx.\r\nnginx\/Gemfile\r\nnginx\/Rakefile\r\nnginx\/examples\r\nnginx\/examples\/init.pp\r\nnginx\/manifests\r\nnginx\/manifests\/init.pp\r\nnginx\/spec\r\nnginx\/spec\/classes\r\nnginx\/spec\/classes\/init_spec.rb\r\nnginx\/spec\/spec_helper.rb\r\nnginx\/README.md\r\nnginx\/metadata.json<\/pre>\n<p>W katalogu z modu\u0142ami pojawi\u0142 si\u0119 nowy modu\u0142:<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppmaster modules]# ls\r\napache concat ntp nginx stdlib<\/pre>\n<p>Szkielet naszego modu\u0142u sk\u0142ada si\u0119 z takich plik\u00f3w i katalog\u00f3w:<\/p>\n<pre class=\"lang:sh decode:true \">[root@ppmaster modules]# cd nginx\r\n[root@ppmaster ssh]# ls\r\nexamples Gemfile manifests metadata.json Rakefile README.md spec<\/pre>\n<p>W pliku<code> metadata.json<\/code> znajduj\u0105 si\u0119 opcje wpisywane przez nas w czasie generowania modu\u0142u. Brakuje tutaj katalogu <code>files<\/code> i <code>templates<\/code>, kt\u00f3re musimy utworzy\u0107 r\u0119cznie.<\/p>\n<p>Wy\u015blijmy teraz do repozytorium git nasz modu\u0142:<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppmaster ssh]# git init\r\nInitialized empty Git repository in \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/.git\/\r\n\r\n[root@ppmaster ssh]# git add .\r\n\r\n[root@ppmaster ssh]# git commit -am \"Init commit\"\r\n[master (root-commit) 62cd417] Init commit\r\nCommitter: root &lt;root@ppmaster.example.com&gt;\r\nYour name and email address were configured automatically based\r\non your username and hostname. Please check that they are accurate.\r\nYou can suppress this message by setting them explicitly:\r\ngit config --global user.name \"Your Name\"\r\ngit config --global user.email you@example.com\r\nAfter doing this, you may fix the identity used for this commit with:\r\ngit commit --amend --reset-author\r\n8 files changed, 215 insertions(+)\r\ncreate mode 100644 Gemfile\r\ncreate mode 100644 README.md\r\ncreate mode 100644 Rakefile\r\ncreate mode 100644 examples\/init.pp\r\ncreate mode 100644 manifests\/init.pp\r\ncreate mode 100644 metadata.json\r\ncreate mode 100644 spec\/classes\/init_spec.rb\r\ncreate mode 100644 spec\/spec_helper.rb\r\n\r\n[root@ppmaster ssh]# git remote add origin git@github.com:mborodziuk\/puppet-nginx.git\r\n\r\n[root@ppmaster ssh]# git push origin master\r\nWarning: Permanently added the RSA host key for IP address '192.30.253.113' to the list of known hosts.\r\nCounting objects: 14, done.\r\nDelta compression using up to 4 threads.\r\nCompressing objects: 100% (11\/11), done.\r\nWriting objects: 100% (14\/14), 4.02 KiB | 0 bytes\/s, done.\r\nTotal 14 (delta 0), reused 0 (delta 0)\r\nTo git@github.com:<em>GIT_ACCOUNT_NAME<\/em>\/puppet-nginx.git\r\n* [new branch] master -&gt; master<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Klasy.<\/span><\/p>\n<p>To nazwane bloki kodu <em>Puppeta<\/em>, kt\u00f3re s\u0105 u\u017cywane w modu\u0142ach. Nie s\u0105 u\u017cywane dop\u00f3ki nie zostan\u0105 wywo\u0142ane. Mog\u0105 by\u0107 dodane w katalogu w\u0119z\u0142a przez zadeklarowanie ich w manife\u015bcie. U\u017cywaj\u0105 zasob\u00f3w do konfigurowania pakiet\u00f3w, plik\u00f3w, us\u0142ug, etc. U\u017cywaj\u0105 parametr\u00f3w do korzystania z zewn\u0119trznych danych. Mog\u0105 by\u0107 u\u017cyte na danym w\u0119\u017ale tylko jeden raz.<\/p>\n<p>Sk\u0142adnia klasy wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<pre class=\"lang:sh decode:true\">class &lt;CLASS_NAME&gt; (\r\n   &lt;DATA_TYPE&gt; &lt;PARAM_NAME&gt;\r\n){\r\n... puppet code ...\r\n}<\/pre>\n<p>Nazwa klasy sk\u0142ada si\u0119 z segment\u00f3w, kt\u00f3re mog\u0105 zwiera\u0107 tylko ma\u0142e litery, cyfry i podkre\u015blenia. Segmenty \u0142\u0105czy\u0107 mo\u017cemy podw\u00f3jnym znakiem dwukropka &#8220;::&#8221;. Pierwszy segment nazwy klasy okre\u015bla modu\u0142. Ostatni segment okre\u015bla nazw\u0119 pliku. Ka\u017cdy dodatkowy segment w nazwie pomi\u0119dzy pomi\u0119dzy pierwszym i ostatnim cz\u0142onem nazwy b\u0119dzie dodatkowym podkatalogiem, np.<\/p>\n<p><code>apache - &lt;MODULE_DIRECTORY&gt;\/apache\/manifest\/init.pp<\/code><\/p>\n<p><code>apache::mod - &lt;MODULE_DIRECTORY&gt;\/apache\/manifest\/mod.pp<\/code><\/p>\n<p><code>apache::mod::passenger - &lt;MODULE_DIRECTORY&gt;\/apache\/manifest\/mod\/passenger.pp<\/code><\/p>\n<p>Gdzie\u00a0<code> &lt;MODULE_DIRECTORY&gt;<\/code> to <code>\/etc\/puppetlabs\/code\/environments\/production\/modules<\/code><\/p>\n<p>Po wygenerowaniu przez nas wcze\u015bniej modu\u0142u <em>ssh<\/em> definicja klasy <em>ssh<\/em> znajduje si\u0119 w pliku <code>\/etc\/puppetlabs\/code\/environments\/production\/modules\/ssh\/manifest\/init.pp<\/code>.<\/p>\n<p>Modyfikujemy j\u0105 tak, aby wygl\u0105da\u0142a nast\u0119puj\u0105co:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx {\r\n class { 'nginx::install': } -&gt; \r\n class { 'nginx::service': }\r\n}<\/pre>\n<p>Ka\u017cda klasa powinna znajdowa\u0107 si\u0119 w swoim w\u0142asnym pliku z rozszerzeniem .pp. W przeciwnym razie <em>Puppet<\/em> zwr\u00f3ci komunikat o b\u0142\u0119dzie.<\/p>\n<p>Zak\u0142adamy zatem plik <code>\/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/manifest\/install.pp<\/code> o tre\u015bci:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::install {\r\n  package { 'epel-release':\r\n    ensure =&gt; installed,\r\n  }-&gt;\r\n  package { 'httpd':\r\n    ensure =&gt; absent,\r\n  }-&gt;\r\n  package { 'nginx': \r\n    ensure =&gt; present, \r\n  } \r\n}<\/pre>\n<p>oraz w tym samym katalogu plik <code>service.pp<\/code> :<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::service {\r\n   service { 'nginx':\r\n      ensure     =&gt; running,\r\n      enable     =&gt; true,\r\n      hasstatus  =&gt; true,\r\n      hasrestart =&gt; true,\r\n      }\r\n}<\/pre>\n<p>Sprawdzamy sk\u0142adnie naszej klasy:<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppmaster manifests]# puppet parser validate init.pp\r\n[root@ppmaster manifests]# puppet parser validate install.pp\r\n[root@ppmaster manifests]# puppet parser validate service.pp\r\n[root@ppmaster manifests]# puppet parser validate user.pp\r\n[root@ppmaster manifests]#<\/pre>\n<p>Na wyj\u015bciu nie ma \u017cadnych komunikat\u00f3w a zatem sk\u0142adnia jest poprawna. Tym samym ca\u0142y kod dotycz\u0105cy <em>nginx<\/em> przenie\u015bli\u015bmy z pliku <code>site.pp<\/code> do wygenerowanego modu\u0142u.<\/p>\n<p>Plik\u00a0<code>\/etc\/puppetlabs\/code\/environments\/production\/manifests\/site.pp<\/code> mo\u017cemy teraz zmodyfikowa\u0107 tak aby wczytywa\u0142 tylko utworzony przez nas wcze\u015bniej modu\u0142 <em>nginx<\/em>:<\/p>\n<pre class=\"lang:sh decode:true \">node 'ppagent1.example.com' {\r\n  include nginx\r\n}\r\n\r\nnode default {  \r\n  user { 'user1': \r\n    ensure     =&gt; present, \r\n    comment    =&gt; 'First and Second Name', \r\n    home       =&gt; '\/home\/user1', \r\n    managehome =&gt; true, \r\n    } \r\n  ssh_authorized_key { 'user1': \r\n    user =&gt; 'user1', \r\n    type =&gt; 'rsa', \r\n    key  =&gt; 'AAAAB3NzaC1yc2EAAAABIwAAAIEA3ATqENg+GWACa2BzeqTdGnJhNoBer8x6pfWkzNzeM8Zx7\/2Tf2pl7kHdbsiTXEUawqzXZQtZzt\/j3Oya+PZjcRpWNRzprSmd2UxEEPTqDw9LqY5S2B8og\/NyzWaIYPsKoatcgC7VgYHplcTbzEhGu8BsoEVBGYu3IRy5RkAcZik=', \r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Operatory.<\/span><\/p>\n<ul>\n<li><code>=<\/code> Przypisanie<\/li>\n<li><code>==<\/code> R\u00f3wno\u015b\u0107<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">$eggs == '61'<\/pre>\n<ul>\n<li><code>=!<\/code> Nier\u00f3wno\u015b\u0107<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">$username != 'FOTHERINGTON-THOMAS'<\/pre>\n<ul>\n<li><code> &gt;<\/code>\u00a0 wi\u0119kszy ni\u017c<\/li>\n<li>\u00a0<code>&lt;<\/code> mniejszy ni\u017c<\/li>\n<li><code> &gt;=<\/code> wi\u0119kszy lub r\u00f3wny ni\u017c<\/li>\n<li><code> &lt;=<\/code> mniejszy lub r\u00f3wny ni\u017c<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">if $eggs &gt;= 61 {\r\n  notify { 'YOU KNOW I GOT NO SENSE OF EGGS': }\r\n}<\/pre>\n<p>Operator por\u00f3wnania wyst\u0119puje r\u00f3wnie\u017c w \u0142a\u0144cuchach, jest to operator &#8220;<code>in<\/code>&#8220;:<\/p>\n<pre class=\"lang:sh decode:true \">if 'eggs' in 'Can you believe the price of eggs?' {\r\n...\r\n}<\/pre>\n<ul>\n<li>Boolean<\/li>\n<\/ul>\n<p>Przyk\u0142ady:<\/p>\n<pre class=\"lang:sh decode:true\">$eggs &gt; 61 and $eggs &lt; 100\r\n$eggs &gt; 61 or $today == 'Thursday'\r\n$today == 'Thursday' and ($eggs &lt; 61 or $eggs &gt; 100)\r\n($today == 'Thursday' and $eggs &lt; 61) or $eggs &gt; 100<\/pre>\n<ul>\n<li>Arytmetyka: dodawanie (<code>+<\/code>), odejmowanie (<code>-<\/code>), mno\u017cenie (<code>*<\/code>), dzielenie (<code>\/<\/code>).<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true \">$celsius = ($fahrenheit - 32) * 5 \/ 9<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Wyra\u017cenia warunkowe.<\/span><\/p>\n<p>Bardzo u\u017cyteczne jest wykonywanie r\u00f3\u017cnych operacji w zale\u017cno\u015bci od warto\u015bci pewnych zmiennych lub wyra\u017ce\u0144. <em>Puppet<\/em> pozwala robi\u0107 to na wiele r\u00f3\u017cnych sposob\u00f3w.<\/p>\n<ul>\n<li><em>If, elsif, else<\/em><\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">if EXPRESSION {\r\n  OPTIONAL_SOMETHING\r\n} \r\nelsif ANOTHER_EXPRESSION {\r\n  OPTIONAL_SOMETHING_ELSE\r\n} \r\nelse {\r\n  OPTIONAL_OTHER_THING\r\n}<\/pre>\n<p>Przyk\u0142ad:<\/p>\n<pre class=\"lang:sh decode:true\">if $::processorcount &gt;= 16 {\r\n  include cpu_intensive_application\r\n} \r\nelsif $::processorcount &gt;= 4 {\r\n  include medium_application\r\n} \r\nelse {\r\n  include lightweight_application\r\n}<\/pre>\n<ul>\n<li><em>unless<\/em><\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">unless EXPRESSION {\r\n  OPTIONAL_SOMETHING\r\n}<\/pre>\n<ul>\n<li><em>case<\/em><\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">case EXPRESSION {\r\n  CASE1 { BLOCK1 }\r\n  CASE2 { BLOCK2 }\r\n  CASE3 { BLOCK3 }\r\n  ...\r\n  default : { ... }\r\n}<\/pre>\n<p>Np. konstrukcj\u0119 if:<\/p>\n<pre class=\"lang:sh decode:true\">if $::operatingsystem == 'Ubuntu' {\r\n  include os_specific::ubuntu\r\n} \r\nelsif $::operatingsystem == 'Debian' {\r\n  include os_specific::debian\r\n} \r\nelsif $::operatingsystem == 'RedHat' {\r\n  include os_specific::redhat\r\n} \r\nelse {\r\n  include os_specific::default\r\n}<\/pre>\n<p>mo\u017cna zast\u0105pi\u0107 konstrukcj\u0105 case:<\/p>\n<pre class=\"lang:sh decode:true\">case $::operatingsystem {\r\n  'Ubuntu': { include os_specific::ubuntu }\r\n  'Debian': { include os_specific::debian }\r\n  'RedHat': { include os_specific::redhat }\r\n  default : { include os_specific::default }\r\n}<\/pre>\n<p>Inny przyk\u0142ad <em>case<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\">case $::operatingsystem {\r\n  'Ubuntu': {\r\n    $os_type = 'Debianlike'\r\n  }\r\n  'RedHat', 'CentOS': {\r\n    $os_type = 'Redhatlike'\r\n  }\r\n  'Darwin': {\r\n    $os_type = 'Mac OS'\r\n  }\r\n  default: {\r\n  $os_type = 'UNKNOWN'\r\n  }\r\n}\r\nnotify { \"You're running a ${os_type} system\": }<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Facter.<\/span><\/p>\n<p><em>Facter<\/em> to narz\u0119dzie, kt\u00f3re dostarcza informacje o systemie. Wszystkie dost\u0119pne informacje o systemie mog\u0105 by\u0107 wy\u015bwietlone po wpisaniu komendy:<\/p>\n<pre class=\"lang:sh decode:true \"># facter<\/pre>\n<p>U\u017cyjmy <em>factera<\/em> w niedawno utworzonym module. W tym celu zak\u0142adamy i edytujemy plik <code>\/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/manifest\/params.pp<\/code><\/p>\n<pre class=\"lang:sh decode:true\">class nginx::params {\r\n   case $facts['os']['family'] {\r\n      'Debian': {\r\n      $package_name = 'nginx'\r\n      $service_name = 'nginx'\r\n      }\r\n      'RedHat': {\r\n      $package_name = 'nginx'\r\n      $service_name = 'nginx'\r\n      }\r\n      'default': {\r\n      fail(\"${facts['operatingsystem']} is not supported\")\r\n      }\r\n   }\r\n}<\/pre>\n<p>Poza tym zmieniamy zawarto\u015b\u0107<code> init.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx(\r\n   String $package_name = $::nginx::params::package_name,\r\n   String $service_name = $::nginx::params::service_name,\r\n   )\r\n      inherits ::nginx::params {\r\n         class { 'nginx::install': } -&gt;\r\n         class { 'nginx::service': }\r\n         }\r\n<\/pre>\n<p>Zmieniamy tak\u017ce plik<code> install.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::install (\r\n   String $package_name = $::nginx::params::package_name,\r\n   ){\r\n      package { 'epel-release': \r\n        ensure =&gt; installed, \r\n        }-&gt; \r\n      package { 'httpd': \r\n        ensure =&gt; absent, \r\n        }-&gt;\r\n      package { 'nginx-package':\r\n         ensure =&gt; present,\r\n         name =&gt; $package_name,\r\n         }\r\n    }<\/pre>\n<p>oraz <code>service.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true \">class nginx::service(\r\n   String $service_name = $::nginx::params::service_name,\r\n   ){\r\n   service { 'nginx-service':\r\n      ensure =&gt; running,\r\n      name =&gt; $service_name,\r\n      enable =&gt; true,\r\n      hasstatus =&gt; true,\r\n      hasrestart =&gt; true,\r\n      }\r\n}<\/pre>\n<p>Walidacja poprawno\u015bci sk\u0142adni:<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppmaster manifests]# puppet parser validate init.pp\r\n[root@ppmaster manifests]# puppet parser validate params.pp\r\n[root@ppmaster manifests]# puppet parser validate install.pp\r\n[root@ppmaster manifests]# puppet parser validate service.pp<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Typy danych.<\/span><\/p>\n<p>Podstawowe typy danych u\u017cywane w <em>Puppecie<\/em> to:<\/p>\n<ul>\n<li>String &#8211; \u0142a\u0144cuch<\/li>\n<li>Integer, Float, Numeric<\/li>\n<li>Boolean<\/li>\n<li>Array &#8211; tablica<\/li>\n<li>Hash<\/li>\n<li>Regexp<\/li>\n<li>Undef<\/li>\n<li>Default<\/li>\n<\/ul>\n<p>Abstrakcyjne typy danych u\u017cywane przez <em>Puppeta<\/em>:<\/p>\n<ul>\n<li>Scalar &#8211; inaczej<code><\/code><em>Integer, Float, String, Boolean, Regexp<\/em><\/li>\n<li>Collection &#8211; tablica lub hash<\/li>\n<li>Variant &#8211; dowolna ilo\u015b\u0107 r\u00f3\u017cnych typ\u00f3w danych<\/li>\n<li>Data &#8211; tak jak Scalar plus dodatkowo undef, tablice i hashe<\/li>\n<li>Pattern &#8211; wzorzec<\/li>\n<li>Enum &#8211; zawiera wcze\u015bniej okre\u015blone stringi<\/li>\n<li>Tuple &#8211; tablica, kt\u00f3ra mo\u017ce zawiera\u0107 r\u00f3\u017cne typy danych<\/li>\n<li>Struct &#8211; zawiera hashe<\/li>\n<li>Optional &#8211; dowolny typ danych<\/li>\n<li>Catalogentry &#8211; zawiera zasoby i klasy<\/li>\n<li>Any &#8211; dowolna warto\u015b\u0107 dowolnego typu danych<\/li>\n<li>Callable &#8211; lambdy dostarczone jako argumenty funkcji<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Wyra\u017cenie regularne.<\/span><\/p>\n<p>W <em>Puppecie<\/em> s\u0105 r\u00f3\u017cne sposoby na testowanie \u0142a\u0144cuch\u00f3w znak\u00f3w.<\/p>\n<p>Np.<\/p>\n<pre class=\"lang:sh decode:true\">if $role == 'webserver' {\r\n  ...\r\n}<\/pre>\n<p>lub<\/p>\n<pre class=\"lang:sh decode:true\">if 'dunk' in 'doughnuts' {\r\n  ...\r\n}<\/pre>\n<p>Je\u017celi natomiast chcemy sprawdzi\u0107 czy w \u0142a\u0144cuchu wyst\u0119puje jaki\u015b wzorzec to musimy si\u0119 pos\u0142u\u017cy\u0107 wyra\u017ceniami regularnymi.<\/p>\n<p>Wzorzec pasuje:<code>  VALUE =~ \/REGEX\/<\/code><br \/>\nWzorzec nie pasuje: <code>VALUE !~ \/REGEX\/<\/code><\/p>\n<p>Np. wyra\u017cenie:<\/p>\n<pre class=\"lang:sh decode:true\">if $::hostname =~ \/app.*staging\/ {\r\n  ...\r\n}<\/pre>\n<p>b\u0119dzie prawdziwe je\u017celi string<em> $::hostname<\/em> przyjmie dowoln\u0105 poni\u017csz\u0105 warto\u015b\u0107:<\/p>\n<ul>\n<li><em>\u008bapp_staging<\/em><\/li>\n<li><em> app-1-staging<\/em><\/li>\n<li><em> application_staging<\/em><\/li>\n<li><em> appstaging<\/em><\/li>\n<li><em> my_app_staging_server<\/em><\/li>\n<\/ul>\n<p>Je\u017celi zachodzi potrzeba odnie\u015b\u0107 si\u0119 do tekstu, kt\u00f3ry by\u0142 wyszukany przez wyra\u017cenie regularne to mo\u017cna to zrobi\u0107 zmienn\u0105 <code>$0<\/code>, np.<\/p>\n<pre class=\"lang:sh decode:true\">$uname = generate('\/usr\/bin\/uname','-a')\r\nif $uname =~ \/\\d+\\.\\d+\\.\\d+\/ {\r\n  notify { \"I have kernel version ${0}\": }\r\n}\r\n\r\nNotice: I have kernel version 3.2.0<\/pre>\n<p>Je\u017celi jest potrzeba odniesienia si\u0119 do jakiej\u015b cz\u0119\u015bci wyszukanego przez wzorzec tekstu to nale\u017cy go zamkn\u0105\u0107 w nawias, np:<\/p>\n<pre class=\"lang:sh decode:true\">$uname = generate('\/usr\/bin\/uname','-a')\r\n  if $uname =~ \/(\\d+)\\.\\d+\\.\\d+\/ {\r\n    notify { \"I have kernel version ${0}, major version ${1}\": }\r\n}\r\n\r\nNotice: I have kernel version 3.2.0, major version 3<\/pre>\n<p>Odwo\u0142anie do ka\u017cdego nast\u0119pnego nawiasu b\u0119dzie si\u0119 odbywa\u0107 przez zmienne <code>$2<\/code>, <code>$3<\/code> itd.<\/p>\n<p>Wyra\u017cenia regularne zaimplementowane w <em>Puppecie<\/em> wywodz\u0105 si\u0119 z j\u0119zyka Ruby. Wi\u0119cej o ich sk\u0142adni mo\u017cna poczyta\u0107 w tym <a href=\"http:\/\/www.tutorialspoint.com\/ruby\/ruby_regular_expressions.htm\" target=\"_blank\" rel=\"noopener noreferrer\">tutorialu.<\/a><\/p>\n<p>Wyra\u017cenia regularne mog\u0105 by\u0107 stosowane w okre\u015blaniu w\u0119z\u0142\u00f3w, np. zamiast zapisu:<\/p>\n<pre class=\"lang:sh decode:true\">node 'demo1', 'demo2', 'demo3' {\r\n  ...\r\n}<\/pre>\n<p>mo\u017cemy zapisa\u0107:<\/p>\n<pre class=\"lang:sh decode:true\">node \/demo.*\/ {\r\n  ...\r\n}<\/pre>\n<p>Przydaje si\u0119 to gdy mamy pewn\u0105 ilo\u015b\u0107 serwer\u00f3w wykonuj\u0105cych te same zadania o podobnych nazwach:<\/p>\n<pre class=\"lang:sh decode:true\">node \/web.*\/ {\r\n  include webserver\r\n}\r\nnode \/app.*\/ {\r\n  include appserver\r\n}\r\nnode \/db.*\/ {\r\n  include dbserver\r\n}<\/pre>\n<p>W wyra\u017ceniach warunkowych tak\u017ce mo\u017cna u\u017cy\u0107 wyra\u017ce\u0144 regularnych, np. zawarto\u015b\u0107 <code>params.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::params {\r\n   case $facts['os']['family'] {\r\n      \/^(Debian|Ubuntu)$\/: {\r\n      $package_name = 'nginx'\r\n      $service_name = 'nginx'\r\n      }\r\n      'RedHat', 'CentOS': {\r\n      $package_name = 'nginx'\r\n      $service_name = 'nginx'\r\n      }\r\n      'default': {\r\n      fail(\"${facts['operatingsystem']} is not supported\")\r\n      }\r\n   }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Tablice.<\/span><\/p>\n<p>Przy pomocy tablic mo\u017cemy grupowa\u0107 zasoby, np.:<\/p>\n<pre class=\"lang:sh decode:true\">package { [ 'php5-cli', 'php5-fpm', 'php-pear' ]:\r\n  ensure =&gt; installed,\r\n}<\/pre>\n<p>Przypisanie zmiennej tablicy:<\/p>\n<pre class=\"lang:sh decode:true \">$developers = ['jerry', 'george', 'elaine']<\/pre>\n<p>Wywo\u0142anie:<\/p>\n<pre class=\"lang:sh decode:true \">notify { $developers: }<\/pre>\n<p>zwr\u00f3ci:<\/p>\n<pre class=\"lang:sh decode:true \">Notice: george\r\nNotice: jerry\r\nNotice: elaine<\/pre>\n<p>Interpolacja tablicy w \u0142a\u0144cuch:<\/p>\n<pre class=\"lang:sh decode:true\">$developers = ['jerry', 'george', 'elaine']\r\n\r\nnotify { \"The developers are: ${developers}\": }\r\nNotice: The developers are: jerrygeorgeelaine<\/pre>\n<p>Odniesienie si\u0119 do konkretnego elementu tablicy:<\/p>\n<pre class=\"lang:sh decode:true \">$developers[0]<\/pre>\n<p>Mo\u017cna pos\u0142ugiwa\u0107 si\u0119 tak\u017ce ujemnymi indeksami:<\/p>\n<pre class=\"lang:sh decode:true\">$developers = ['jerry', 'george', 'elaine']\r\n\r\nnotify { \"The last developer is: ${developers[-1]}\": }\r\nNotice: The last developer is: elaine<\/pre>\n<p>Operator <code>in<\/code> dzia\u0142a r\u00f3wnie\u017c w tablicach:<\/p>\n<pre class=\"lang:sh decode:true\">if $crewmember in ['Frank', 'Dave'] {\r\n  notify { \"I'm sorry, ${crewmember}. I'm afraid I can't do that.\": }\r\n}<\/pre>\n<p>Odnosz\u0105c si\u0119 do zmiennej w innym stringu zmienn\u0105 owijamy w nawiasy klamrowe, np. <code>${crewmember}<\/code>.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\"> Hashe.<\/span><\/p>\n<p>Hashe to zbi\u00f3r par element\u00f3w:<code> klucz =&gt; warto\u015b\u0107<\/code>. W <em>Puppecie<\/em> hash wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<pre class=\"lang:sh decode:true\">$interfaces = {\r\n  'lo0' =&gt; '127.0.0.1',\r\n  'eth0' =&gt; '192.168.0.1',\r\n}<\/pre>\n<p>Odniesienie si\u0119 do konkretnej pozycji w hashu:<\/p>\n<pre class=\"lang:sh decode:true\">$address = $interfaces['eth0']\r\n\r\nnotify { \"Interface eth0 has address ${address}\": }\r\nNotice: Interface eth0 has address 192.168.0.1<\/pre>\n<p>Kluczem w hashu musi by\u0107 string ale warto\u015bci mog\u0105 by\u0107 dowolnego typu:<\/p>\n<pre class=\"lang:sh decode:true\">$contrived_example = {\r\n  'fish' =&gt; 'babel',\r\n  'answer' =&gt; 42,\r\n  'crew' =&gt; ['Ford Prefect', 'Arthur Dent'],\r\n  'hash' =&gt; { 'Warning' =&gt; 'Beware of the leopard' }\r\n}<\/pre>\n<p>Poniewa\u017c warto\u015bci w hashu mog\u0105 by\u0107 tak\u017ce innymi hashami to mo\u017cna konstruowa\u0107 wielopoziomowe hashe, np:<\/p>\n<pre class=\"lang:sh decode:true\">$interfaces = {\r\n  'lo0' =&gt; {\r\n    'address' =&gt; '127.0.0.1',\r\n    'netmask' =&gt; '255.0.0.0',\r\n  },\r\n  'eth0' =&gt; {\r\n  'address' =&gt; '192.168.0.1',\r\n  'netmask' =&gt; '255.255.255.0',\r\n  }\r\n}\r\n$eth0_netmask = $interfaces['eth0']['netmask']\r\n\r\nnotify { \"eth0 has netmask ${eth0_netmask}\": }\r\n\r\nNotice: eth0 has netmask 255.255.255.0<\/pre>\n<p>Sprawdza\u0107 czy dany klucz wyst\u0119puje w hashu mo\u017cemy wyra\u017ceniem:<\/p>\n<pre class=\"lang:sh decode:true \">if 'eth0' in $interfaces {\r\n  ...\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Pliki.<\/span><\/p>\n<p><em>Nginx<\/em> jest zainstalowany i uruchomiony ale nie serwuje strony web. Tworzymy na masterze zatem struktur\u0119 katalog\u00f3w i plik <code>index.html<\/code> dla serwowanej strony.<\/p>\n<pre class=\"lang:sh decode:true\"># mkdir -p \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/files\/website\r\n# echo 'This is website' &gt; \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/files\/website\/index.html\r\n<\/pre>\n<p>Utworzenie pliku <code>\/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/files\/example.conf <\/code>z konfiguracj\u0105 strony:<\/p>\n<pre class=\"lang:sh decode:true\">server {\r\n  listen 80;\r\n  root \/var\/www\/example;\r\n  server_name example.com;\r\n}<\/pre>\n<p>Zak\u0142adamy nowy plik <code>\/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/manifests\/config.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true \">class nginx::config {\r\n  file { '\/etc\/nginx\/default.d\/default':\r\n    ensure =&gt; file,\r\n    mode   =&gt; '0600',\r\n    owner  =&gt; 'root',\r\n    group  =&gt; 'root',\r\n    source =&gt; 'puppet:\/\/\/modules\/nginx\/example.conf',\r\n  }\r\n  file { '\/var\/www': \r\n    ensure =&gt; directory, \r\n    mode =&gt; '0755', \r\n    owner =&gt; 'root', \r\n    group =&gt; 'root', \r\n  }\r\n  file { '\/var\/www\/example': \r\n    source =&gt; 'puppet:\/\/\/modules\/nginx\/files\/website',\r\n    recurse =&gt; true,\r\n    require =&gt; File['\/var\/www'],\r\n    }\r\n}<\/pre>\n<p>Atrybut <code>recurse<\/code> pozwala na skopiowanie ca\u0142ego katalogu website wraz z zawarto\u015bci\u0105 do \/var\/www pod nazw\u0105 example. Zwr\u00f3\u0107my uwag\u0119, \u017ce warto\u015b\u0107 atrybutu <em>source <\/em> <code>puppet:\/\/\/modules\/nginx\/example.conf<\/code> zaczyna si\u0119 od trzech uko\u015bnik\u00f3w a nie dw\u00f3ch co oznacza, \u017ce plik <em>puppeta<\/em>, na kt\u00f3ry wskazuje atrybut jest na lokalnym ho\u015bcie, poniewa\u017c zapis <code>puppet:\/\/\/modules\/nginx\/example.conf<\/code> jest r\u00f3wnowa\u017cny z<code> puppet:\/\/\/modules\/nginx\/example.conf.<\/code><\/p>\n<p>Edytujemy plik <code>init.pp<\/code> .<\/p>\n<pre class=\"lang:sh decode:true\">class nginx(\r\n  String $package_name = $::nginx::params::package_name,\r\n  String $service_name = $::nginx::params::service_name,\r\n  )\r\n  inherits ::nginx::params {\r\n    class { 'nginx::install': } -&gt;\r\n    class { 'nginx::config': } ~&gt;\r\n    class { 'nginx::service': }\r\n  }<\/pre>\n<p>Znak ~&gt; to odpowiednik atrybutu <code>notify =&gt; Service['nginx']<\/code>, nakazuje puppetowi aby zrestartowa\u0142 si\u0119 po ka\u017cdej zmianie zawarto\u015bci pliku <code>example.conf<\/code>. Kod jest r\u00f3wnowa\u017cny z:<\/p>\n<pre class=\"lang:sh decode:true\">node 'ppagent1.example.com' {\r\n  package { 'epel-release':\r\n    ensure =&gt; installed,\r\n  }-&gt;\r\n  package { 'httpd':\r\n    ensure =&gt; absent,\r\n  }-&gt;\r\n  package { 'nginx':\r\n    ensure =&gt; installed,\r\n  }\r\n  service { 'nginx': \r\n    ensure =&gt; running, \r\n    require =&gt; Package['nginx'], \r\n  }\r\n  file { '\/etc\/nginx\/default.d\/default': \r\n    source =&gt; 'puppet:\/\/\/etc\/puppetlabs\/code\/environments\/production\/example.conf', \r\n    notify =&gt; Service['nginx'],\r\n  }\r\n}\r\n<\/pre>\n<p>Co z koleji jest r\u00f3wnowa\u017cne z:<\/p>\n<pre class=\"lang:sh decode:true\">node 'ppagent1.example.com' {\r\n  package { 'epel-release':\r\n    ensure =&gt; installed,\r\n  }-&gt;\r\n  package { 'httpd':\r\n    ensure =&gt; absent,\r\n  }-&gt;\r\n  package { 'nginx':\r\n    ensure =&gt; installed,\r\n  }\r\n  file { '\/etc\/nginx\/default.d\/default': \r\n    source =&gt; 'puppet:\/\/\/etc\/puppetlabs\/code\/environments\/production\/example.conf', \r\n  }\r\n  service { 'nginx': \r\n    ensure    =&gt; running, \r\n    require   =&gt; Package['nginx'],\r\n    subscribe =&gt; File['\/etc\/nginx\/default.d\/default'],\r\n  }\r\n}\r\n<\/pre>\n<p>Czyli us\u0142uga niginx b\u0119dzie subskrybowa\u0107 plik <code>\/etc\/nginx\/default.d\/default<\/code>. Je\u017celi zmieni si\u0119 zawarto\u015b\u0107 tego pliku to us\u0142uga si\u0119 prze\u0142aduje.<\/p>\n<p>Do zarz\u0105dzania konfiguracj\u0105 wybranego pakietu cz\u0119sto u\u017cywany jest nast\u0119puj\u0105cy wzorzec.<\/p>\n<pre class=\"lang:sh decode:true\">package { THE_STUFF: \r\n  ensure =&gt; installed, \r\n}\r\nservice { THE_STUFF: \r\n  ensure  =&gt; running, \r\n  require =&gt; Package[THE_STUFF], \r\n}\r\nfile { '\/etc\/THE_STUFF.conf': \r\n   source =&gt; 'puppet:\/\/\/puppet\/modules\/THE_STUFF\/THE_STUFF.conf', \r\n   notify =&gt; Service[THE_STUFF], \r\n}\r\n<\/pre>\n<p>W praktyce <em>Puppet <\/em>jest wolny je\u017celi chodzi o pobieranie ca\u0142ego drzewa katalog\u00f3w pod stron\u0119 web dlatego lepiej u\u017cywa\u0107 GITa jako repozytorium.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Szablony.<\/span><\/p>\n<p>U\u017cytego przez nas pliku konfiguracyjnego <em>nginxa<\/em> <code>example.com<\/code> nie mo\u017cemy niestety wykorzysta\u0107 ponownie poniewa\u017c zawiera on konfiguracj\u0119 tylko dla \u015bci\u015ble okre\u015blonego jednego webserwera. Aby mo\u017cna go by\u0142o u\u017cy\u0107 wielokrotnie musimy przerobi\u0107 go na szablon.<\/p>\n<p>Szablony maj\u0105 roszerzenie <code>.erb<\/code> i sk\u0142adujemy w katalogu:<\/p>\n<pre class=\"lang:sh decode:true\">&lt;MODULES DIRECTORY&gt;\/&lt;MODULE NAME&gt;\/templates\/motd.erb<\/pre>\n<p>ERB to j\u0119zyk tworzenia szablon\u00f3w u\u017cywany przez Ruby.<\/p>\n<p>Zak\u0142adamy katalog z szablonami <em>nginxa<\/em> i wgrywamy do niego nasz plik:<\/p>\n<pre class=\"lang:sh decode:true\"># mkdir \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/templates\r\n# mv \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/files\/example.com   \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/templates\/vhost.conf.erb<\/pre>\n<p>Edytujemy plik <code>vhost.conf.erb<\/code> :<\/p>\n<pre class=\"lang:sh decode:true\">server {\r\n  listen 80;\r\n  root \/var\/www\/&lt;%= @site_name %&gt;;\r\n  server_name &lt;%= @site_domain %&gt;;\r\n}<\/pre>\n<p>Znaki <code>&lt;%= %&gt;<\/code> oznaczaj\u0105, \u017ce w \u015brodku b\u0119dzie zmienna w j\u0119zyku <em>Ruby<\/em>. W naszym przypadku b\u0119dzie tu wstawiona zmienna Ruby. Zmienne te to <code>@site_name<\/code> oraz <code>@site_domain<\/code>. Istnieje tak\u017ce mo\u017cliwo\u015b\u0107 wstawienia ca\u0142ych wyra\u017ce\u0144 w j\u0119zyku Ruby. Robi si\u0119 to przy pomocy konstrukcji, np.:<\/p>\n<pre class=\"lang:sh decode:true\">&lt;% if condition %&gt; ...text.. &lt;% end %&gt;<\/pre>\n<p>Inne konstrukcje, kt\u00f3re mo\u017cna u\u017cywa\u0107 w szablonach ERB to:<\/p>\n<ul>\n<li>komentarz:\n<pre class=\"lang:sh decode:true\"> &lt;%# This is a comment %&gt;<\/pre>\n<\/li>\n<li>p\u0119tla:\n<pre class=\"lang:sh decode:true\">&lt;% @valuse.each do |value -%&gt; \r\nsome value &lt;%= value %&gt; \r\n&lt;% end -%&gt;<\/pre>\n<p>&nbsp;<\/li>\n<\/ul>\n<p>Nasz plik <code>config.pp<\/code> wygl\u0105da\u0107 powinien teraz tak:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::config {\r\n  $site_name = 'example1'\r\n  $site_domain = 'example1.com'\r\n\r\n  file { '\/etc\/nginx\/default.d\/default':\r\n    ensure =&gt; absent,\r\n    }-&gt;\r\n  file { '\/etc\/nginx\/default.d\/example1.com':\r\n    ensure =&gt; file,\r\n    mode   =&gt; '0600',\r\n    owner  =&gt; 'root',\r\n    group  =&gt; 'root',\r\n    content =&gt; template('nginx\/vhost.conf.erb'),\r\n  }\r\n  file { '\/var\/www': \r\n    ensure =&gt; directory, \r\n    mode =&gt; '0755', \r\n    owner =&gt; 'root', \r\n    group =&gt; 'root', \r\n  }\r\n  file { '\/var\/www\/example': \r\n    source =&gt; 'puppet:\/\/\/modules\/nginx\/files\/website',\r\n    recurse =&gt; true,\r\n    require =&gt; File['\/var\/www'],\r\n    }\r\n}<\/pre>\n<p>Dodajmy teraz tryb warunkowy do naszej konfiguracji web serwera aby m\u00f3g\u0142 dzia\u0142a\u0107 nie tylko na porcie 80. Nasz szablon erb niech wygl\u0105da tak:<\/p>\n<pre class=\"lang:sh decode:true\">server {\r\n&lt;% if @standard_port %&gt; listen 80; &lt;% else %&gt; listen 8080; &lt;% end %&gt;\r\nroot \/var\/www\/&lt;%= @site_name %&gt;;\r\nserver_name &lt;%= @site_domain %&gt;;\r\n}<\/pre>\n<p>Oczywi\u015bcie mo\u017cna by\u0142o wpisa\u0107 tutaj po prostu:<\/p>\n<pre class=\"lang:sh decode:true \">listen &lt;%= @port %&gt;;<\/pre>\n<p>ale chcemy wykorzysta\u0107 tryb warunkowy <em>if<\/em>.<\/p>\n<p>Pliki tworz\u0105ce modu\u0142 <em>nginx<\/em> niech wygl\u0105daj\u0105 teraz jak poni\u017cej.<\/p>\n<p><code>params.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::params {\r\n  $standard_port = true\r\n  case $facts['os']['family'] {\r\n    'Debian': {\r\n      $package_name = 'nginx'\r\n      $service_name = 'nginx'\r\n      }\r\n    'RedHat': {\r\n      $package_name = 'nginx'\r\n      $service_name = 'nginx'\r\n      }\r\n    'default': {\r\n      fail(\"${facts['operatingsystem']} is not supported\")\r\n      }\r\n  }\r\n}<\/pre>\n<p><code>init.pp<\/code> :<\/p>\n<pre class=\"lang:sh decode:true\">class nginx(\r\n  Boolean $standard_port = $::nginx::params::standard_port,\r\n  String $package_name   = $::nginx::params::package_name,\r\n  String $service_name   = $::nginx::params::service_name,\r\n  )\r\n  inherits ::nginx::params {\r\n    class { 'nginx::install': } -&gt;\r\n    class { 'nginx::user': } -&gt;\r\n    class { 'nginx::config': } ~&gt;\r\n    class { 'nginx::service': }\r\n}<\/pre>\n<p><code>config.pp<\/code> :<\/p>\n<pre class=\"lang:sh decode:true\">class nginx::config(\r\n  $standard_port = $::nginx::standard_port,\r\n  ){\r\n  $site_name = 'example1'\r\n  $site_domain = 'example1.com'\r\n\r\n  file { '\/etc\/nginx\/default.d\/default':\r\n    ensure =&gt; absent,\r\n    }-&gt;\r\n  file { '\/etc\/nginx\/default.d\/example1.com':\r\n    ensure =&gt; file,\r\n    mode =&gt; '0600',\r\n    owner =&gt; 'root',\r\n    group =&gt; 'root',\r\n    content =&gt; template('nginx\/vhost.conf.erb'),\r\n    }\r\n  file { '\/var\/www':\r\n    ensure =&gt; directory,\r\n    mode =&gt; '0755',\r\n    owner =&gt; 'root',\r\n    group =&gt; 'root',\r\n    }\r\n  file { '\/var\/www\/example':\r\n    source =&gt; 'puppet:\/\/\/modules\/nginx\/website',\r\n    recurse =&gt; true,\r\n    require =&gt; File['\/var\/www'],\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Parametry klasy.<\/span><\/p>\n<p>Poniewa\u017c u\u017cywany przez nas wcze\u015bniej wzorzec przekazywania parametr\u00f3w do klasy <em>&lt;MODULE NAME&gt;::params<\/em> zosta\u0142 zdeprecjonowany musimy te parametry przekaza\u0107 w inny spos\u00f3b. Rekomendowanym sposobem jest teraz u\u017cywanie funkcji lub <em>Hiera<\/em>, o kt\u00f3rej napisze w innych artyku\u0142ach. Funkcja, o kt\u00f3re mowa to <em>Function Data Provider<\/em> &#8211;\u00a0<em>&lt;MODULE NAME&gt;::<\/em>data, podobna do u\u017cywanej wcze\u015bniej params.pp.<\/p>\n<p><em>Function Data Provider<\/em> mo\u017ce by\u0107:<\/p>\n<ul>\n<li>napisana\u00a0 w j\u0119zyku <em>Puppeta<\/em> i zlokalizowana w pliku <code>&lt;MODULE ROOT&gt;\/functions\/data.pp<\/code><\/li>\n<li>napisana w j\u0119zyku Ruby i zlokalizowana w<code> &lt;MODULE ROOT&gt;\/lib\/puppet\/functions\/&lt;MODULE NAME&gt;\/data.rb<\/code>.<\/li>\n<\/ul>\n<p>Stw\u00f3rzmy teraz tak\u0105 funkcj\u0119 napisan\u0105 w j\u0119zyku Puppeta.<\/p>\n<pre class=\"lang:sh decode:true\"># cd \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\r\n# mkdir functions\r\n# cd functions\r\n# vim data.pp<\/pre>\n<p>Plik <code>data.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">function nginx::data {\r\n  $base_params = {\r\n    'nginx::ensure'         =&gt; 'present',\r\n    'nginx::service_enable' =&gt; true,\r\n    'nginx::service_ensure' =&gt; 'running',\r\n    'nginx::site_name'      =&gt; 'example3',\r\n    'nginx::site_domain'    =&gt; 'example3.com',\r\n    'nginx::standard_port'  =&gt; true,\r\n  }\r\n  case $facts['os']['family'] {\r\n    'Debian': {\r\n      $os_params = {\r\n        'nginx::package_name' =&gt; 'nginx',\r\n        'nginx::service_name' =&gt; 'nginx',\r\n      }\r\n    }\r\n    'RedHat': {\r\n      $os_params = {\r\n        'nginx::package_name' =&gt; 'nginx',\r\n        'nginx::service_name' =&gt; 'nginx',\r\n      }\r\n    }\r\n    default: {\r\n      fail(\"${facts['operatingsystem']} is not supported\")\r\n    }\r\n  }\r\n  $base_params + $os_params\r\n}<\/pre>\n<p><code>init.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">class nginx(\r\n  String $package_name,\r\n  String $service_name,\r\n  String $ensure,\r\n  String $service_ensure,\r\n  String $site_name,\r\n  String $site_domain,\r\n  Boolean $service_enable,\r\n  Boolean $standard_port,\r\n  ) {\r\n    class { 'nginx::install': } -&gt;\r\n    class { 'nginx::config': } ~&gt;\r\n    class { 'nginx::service': }\r\n}<\/pre>\n<p><code>config.pp:<\/code><\/p>\n<pre class=\"lang:sh decode:true\">class nginx::config(\r\n  Boolean $standard_port = $::nginx::standard_port,\r\n  String $site_name = $::nginx::site_name,\r\n  String $site_domain = $::nginx::site_domain,\r\n  ){\r\n    file { '\/etc\/nginx\/default.d\/default':\r\n      ensure =&gt; absent,\r\n    }-&gt;\r\n    file { \"\/etc\/nginx\/default.d\/${site_domain}\":\r\n      ensure =&gt; file,\r\n      mode =&gt; '0600',\r\n      owner =&gt; 'root',\r\n      group =&gt; 'root',\r\n      content =&gt; template('nginx\/vhost.conf.erb'),\r\n    }\r\n    file { '\/var\/www':\r\n      ensure =&gt; directory,\r\n      mode =&gt; '0755',\r\n      owner =&gt; 'root',\r\n      group =&gt; 'root',\r\n    }\r\n    file { \"\/var\/www\/${site_name}\":\r\n      source =&gt; 'puppet:\/\/\/modules\/nginx\/website',\r\n      recurse =&gt; true,\r\n      require =&gt; File['\/var\/www'],\r\n   }\r\n}<\/pre>\n<p><code>install.pp:<\/code><\/p>\n<pre class=\"lang:sh decode:true\">class nginx::install (\r\n  String $package_name = $::nginx::package_name,\r\n  String $ensure = $::nginx::ensure,\r\n  ){\r\n    package { 'epel-release': ensure =&gt; installed, }-&gt;\r\n    package { 'httpd': ensure =&gt; absent, }-&gt;\r\n    package { 'nginx-package':\r\n      ensure =&gt; $ensure,\r\n      name =&gt; $package_name,\r\n }\r\n}<\/pre>\n<p><code>service.pp:<\/code><\/p>\n<pre class=\"lang:sh decode:true\">class nginx::service(\r\n  String $service_name = $::nginx::service_name,\r\n  String $service_ensure = $::nginx::service_ensure,\r\n  Boolean $service_enable = $::nginx::service_enable,\r\n  ){\r\n  service { 'nginx-service':\r\n    ensure =&gt; $service_ensure,\r\n    name =&gt; $service_name,\r\n    enable =&gt; $service_enable,\r\n    hasstatus =&gt; true,\r\n    hasrestart =&gt; true,\r\n  }\r\n}<\/pre>\n<p>Zmodyfikowa\u0107 musimy tak\u017ce plik<code> metadata.json<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\" style=\"padding-left: 60px;\">{\r\n  \"name\": \"username-nginx\",\r\n  \"version\": \"0.1.0\",\r\n  \"author\": \"mborodziuk\",\r\n  \"summary\": null,\r\n  \"license\": \"Apache-2.0\",\r\n  \"source\": \"https:\/\/github.com\/mborodziuk\/puppet-nginx\",\r\n  \"project_page\": \"https:\/\/github.com\/mborodziuk\/puppet-nginx\",\r\n  \"issues_url\": \"https:\/\/github.com\/mborodziuk\/puppet-nginx\/issues\",\r\n  \"dependencies\": [\r\n   {\"name\":\"puppetlabs-stdlib\",\"version_requirement\":\"&gt;= 1.0.0\"}\r\n  ],\r\n  \"data_provider\": \"function\"\r\n}<\/pre>\n<p><em>data_provider<\/em> zosta\u0142 tu przestawiony na <em>function<\/em>.<\/p>\n<p>Jak wida\u0107 wszystkie parametry modu\u0142u <em>nginx<\/em> mo\u017cna ustawiawiono bezpo\u015brednio w <code>data.pp<\/code>.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Definicje zasob\u00f3w.<\/span><\/p>\n<p>Definicje zasob\u00f3w przydaj\u0105 si\u0119 gdy chcemy grupowa\u0107 zasoby r\u00f3\u017cnych typ\u00f3w. Je\u017celi mamy potrzeb\u0119 wykonania np. takich zada\u0144:<\/p>\n<pre class=\"lang:sh decode:true\">file { '\/usr\/local\/bin\/job1':\r\n  source =&gt; 'puppet:\/\/\/modules\/scripts\/job1',\r\n  mode   =&gt; '0755',\r\n}\r\ncron { 'Run job1':\r\n  command =&gt; '\/usr\/local\/bin\/job1',\r\n  hour    =&gt; '00',\r\n  minute  =&gt; '00',\r\n}\r\nfile { '\/usr\/local\/bin\/job2':\r\n  source =&gt; 'puppet:\/\/\/modules\/scripts\/job2',\r\n  mode   =&gt; '0755',\r\n}\r\ncron { 'Run job2':\r\n  command =&gt; '\/usr\/local\/bin\/job2',\r\n  hour    =&gt; '00',\r\n  minute  =&gt; '00',\r\n}<\/pre>\n<p>To najlepiej zdefiniowa\u0107 taki zas\u00f3b:<\/p>\n<pre class=\"lang:sh decode:true\"># Manages a script plus the cron job to run it\r\ndefine script_job() {\r\n  file { \"\/usr\/local\/bin\/${name}\":\r\n  source =&gt; \"puppet:\/\/\/modules\/scripts\/${name}\",\r\n  mode   =&gt; '0755',\r\n}\r\ncron { \"Run ${name}\":\r\n  command =&gt; \"\/usr\/local\/bin\/${name}\",\r\n  hour    =&gt; '00',\r\n  minute  =&gt; '00',\r\n}\r\n}<\/pre>\n<p>A p\u00f3\u017aniej go uruchomi\u0107 w manife\u015bcie:<\/p>\n<pre class=\"lang:sh decode:true \">script_job { 'backup_database':\r\n}<\/pre>\n<p>Mo\u017cna tak\u017ce przekazywa\u0107 parametry do takiego zdefiniowanego zasobu:<\/p>\n<pre class=\"lang:sh decode:true\">define script_job( $hour = '00', $minute = '00') {\r\n  file { \"\/usr\/local\/bin\/${name}\":\r\n    source =&gt; \"puppet:\/\/\/modules\/scripts\/${name}\",\r\n    mode   =&gt; '0755',\r\n  }\r\n  cron { \"Run ${name}\":\r\n    command =&gt; \"\/usr\/local\/bin\/${name}\",\r\n    hour    =&gt; $hour,\r\n    minute  =&gt; $minute,\r\n  }\r\n}<\/pre>\n<p>Uruchomienie z domy\u015blnymi parametrami (<code>$hour = '00', $minute = '00'<\/code>):<\/p>\n<pre class=\"lang:sh decode:true\">script_job { 'backup_database':\r\n}<\/pre>\n<p>Uruchomienie ze swoimi parametrami:<\/p>\n<pre class=\"lang:sh decode:true\">script_job { 'backup_database':\r\n  hour   =&gt; '05',\r\n  minute =&gt; '30',\r\n}<\/pre>\n<p>Uruchomienie z jednym domy\u015blnym (<code>$minute = '00'<\/code>) i jednym swoim parametrem (<code>hour =&gt; \"*\"<\/code>):<\/p>\n<pre class=\"lang:sh decode:true \">script_job { 'download_tweets':\r\n  hour =&gt; \"*\",\r\n}<\/pre>\n<p>Utw\u00f3rzmy taki zdefiniowany zas\u00f3b w naszym module <em>nginx<\/em>, kt\u00f3ry b\u0119dzie odpowiedzialny za backup plik\u00f3w tworz\u0105cych webserver <em>example.com<\/em>.\u00a0 Backup b\u0119dzie wykonywa\u0142 skrypt\u00a0<code>\/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\/files\/scripts\/backup.sh<\/code>. Definicj\u0119 zasobu umieszczamy natomiast w osobnym pliku np. <code>backup.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\"># cd \/etc\/puppetlabs\/code\/environments\/production\/modules\/nginx\r\n# vim backup.pp<\/pre>\n<p>Zawarto\u015b\u0107 pliku <code>backup.pp<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">define nginx::backup(\r\n  String $hour = '00',\r\n  String $minute = '00',\r\n  ) {\r\n    file { '\/scripts':\r\n      ensure =&gt; directory,\r\n      mode   =&gt; '0755',\r\n      owner  =&gt; 'root',\r\n      group  =&gt; 'root',\r\n    }-&gt;\r\n    file { \"\/scripts\/${name}\":\r\n      source =&gt; \"puppet:\/\/\/modules\/nginx\/scripts\/${name}\",\r\n      mode =&gt; '0755',\r\n    }-&gt;\r\n    cron { \"Run ${name}\":\r\n      command =&gt; \"\/scripts\/${name}\",\r\n      hour    =&gt; $hour,\r\n      minute  =&gt; $minute,\r\n    }\r\n}<\/pre>\n<p>Plik <code>config.pp<\/code> modyfikujemy nast\u0119puj\u0105co:<\/p>\n<pre class=\"lang:sh decode:true \">class nginx::config(\r\n  Boolean $standard_port = $::nginx::standard_port,\r\n  String  $site_name     = $::nginx::site_name,\r\n  String  $site_domain   = $::nginx::site_domain,\r\n  ){\r\n    file { '\/etc\/nginx\/default.d\/default':\r\n      ensure =&gt; absent,\r\n    }-&gt;\r\n    file { \"\/etc\/nginx\/default.d\/${site_domain}\":\r\n      ensure =&gt; file,\r\n      mode   =&gt; '0600',\r\n      owner  =&gt; 'root',\r\n      group =&gt; 'root',\r\n      content =&gt; template('nginx\/vhost.conf.erb'),\r\n    }\r\n    file { '\/var\/www':\r\n      ensure =&gt; directory,\r\n      mode =&gt; '0755',\r\n      owner =&gt; 'root',\r\n      group =&gt; 'root',\r\n    }\r\n    file { \"\/var\/www\/${site_name}\":\r\n      source =&gt; 'puppet:\/\/\/modules\/nginx\/website',\r\n      recurse =&gt; true,\r\n      require =&gt; File['\/var\/www'],\r\n    }\r\n    nginx::backup { 'backup.sh':\r\n      hour   =&gt; '01',\r\n      minute =&gt; '00',\r\n    }\r\n}<\/pre>\n<p>Po uruchomieniu na agencie:<\/p>\n<pre class=\"lang:sh decode:true \"># puppet agent -t<\/pre>\n<p>Na agencie pojawi si\u0119 owy skrypt <code>\/scripts\/backup.sh<\/code> a na li\u015bcie zada\u0144 <em>crona<\/em> pojawi si\u0119 nowe zadanie:<\/p>\n<pre class=\"lang:sh decode:true\"># crontab -l\r\n\r\n# # Puppet Name: Run backup.sh\r\n0 1 * * * \/scripts\/backup.sh<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Konfiguracja SSH (OLD).<\/span><\/p>\n<p>Je\u017celi zachodzi potrzeba modyfikacji konfiguracji SSH dla systemu to r\u00f3wnie\u017c mo\u017cna u\u017cy\u0107 Puppeta.<\/p>\n<p>Tworzymy katalogi dla konfiguracji SSH:<\/p>\n<pre class=\"lang:sh decode:true \"># mkdir -p \/puppet\/modules\/ssh\/manifests\r\n# mkdir -p \/puppet\/modules\/ssh\/files<\/pre>\n<p>Zak\u0142adamy plik <code>\/puppet\/modules\/ssh\/manifests\/init.pp<\/code> o tre\u015bci:<\/p>\n<pre class=\"lang:sh decode:true\"># Manage the SSH service\r\nclass ssh {\r\n   service { 'ssh':\r\n      ensure =&gt; running,\r\n   }\r\n   file { '\/etc\/ssh\/sshd_config':\r\n      source =&gt; 'puppet:\/\/\/puppet\/modules\/ssh\/sshd_config',\r\n      notify =&gt; Service['ssh'],\r\n      owner  =&gt; 'root',\r\n      group  =&gt; 'root',\r\n   }\r\n}<\/pre>\n<p>Zak\u0142adamy plik <code>\/puppet\/ modules\/ssh\/files\/sshd_config<\/code> z zawarto\u015bci\u0105:<\/p>\n<pre class=\"lang:sh decode:true\">Port 22\r\nProtocol 2\r\nPermitRootLogin no\r\nPasswordAuthentication no\r\nAllowUsers user1 user2\r\nUsePAM yes<\/pre>\n<p>Do definicji w\u0119z\u0142a <em>server1<\/em> dodajemy wczytywanie nowej klasy <em>ssh<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\">node 'server1' \r\n{ \r\n   include nginx \r\n   include ssh\r\n   user { 'user1': \r\n      ensure     =&gt; present, \r\n      comment    =&gt; 'First and Second Name', \r\n      home       =&gt; '\/home\/user1', \r\n      managehome =&gt; true, \r\n   }\r\n   ssh_authorized_key { 'user1_ssh':\r\n      user =&gt; 'user1',\r\n      type =&gt; 'rsa',\r\n      key  =&gt; 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDozMFm++tr0UFUeHZTT3vqqygsnMcdkIiDDCYQz3140lOjx3kts4lPF41gVU1V6cVoY7yJ3XVMUguEHOEwoMuvUudSurN0ufIxh5H8ZVott27g7aJZGwUdEkdPNX\/U1G+GnQ0dU\/RtPw+oTIaXlnMEG6T9ECmZP8ON5n3uvlpsH\/9t6U19B4t2\/0oPIfu5H+5TgNDbweceun5X39XZm\/PqMOy7A0Ynuh\/4g9iA4VIo2YUrQV7kA2lK6tWQZ1SoJnrMr21NUq8L4fP1KclGcZz2dmRbDSDJNGLPlKjZtwXK+cLGQzvBUpqFjGG8FDx5Lz9AhxhVg\/MiZfXNq1H0mw\/n',\r\n   }\r\n}<\/pre>\n<p>Tak jak po ka\u017cdej zmianie tak i teraz uruchamiamy ponownie <em>papply<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\"># papply<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dalsza cz\u0119\u015b\u0107 kursu traktuj\u0105cego o najpopularniejszym narz\u0119dziu o zarz\u0105dzania konfiguracj\u0105 infrastruktury.<\/p>\n","protected":false},"author":1,"featured_media":1856,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[87],"tags":[],"_links":{"self":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/1752"}],"collection":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/comments?post=1752"}],"version-history":[{"count":104,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/1752\/revisions"}],"predecessor-version":[{"id":3332,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/1752\/revisions\/3332"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media\/1856"}],"wp:attachment":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media?parent=1752"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/categories?post=1752"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/tags?post=1752"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}