{"id":1888,"date":"2017-08-16T12:14:00","date_gmt":"2017-08-16T10:14:00","guid":{"rendered":"http:\/\/miroslaw.borodziuk.eu\/?p=1888"},"modified":"2020-02-13T23:31:30","modified_gmt":"2020-02-13T22:31:30","slug":"puppet-standalone","status":"publish","type":"post","link":"http:\/\/miro.borodziuk.eu\/index.php\/2017\/08\/16\/puppet-standalone\/","title":{"rendered":"J\u0119zyk DSL Puppeta cz.1"},"content":{"rendered":"<p>Za\u0142\u00f3\u017cmy, \u017ce mamy do postawienia kilkaset wirtualnych serwer\u00f3w z okre\u015blonym oprogramowaniem i konfiguracj\u0105. Je\u017celi chcieliby\u015bmy wykona\u0107 to zadanie r\u0119cznie by\u0142oby to bardzo pracoch\u0142onne. W instalacji wirtualnych maszyn pomo\u017ce nam z pewno\u015bci\u0105 <em>Kickstart<\/em>, a z konfiguracj\u0105 tych maszyn mo\u017ce nam pom\u00f3c dowolny menad\u017cer konfiguracji. Najbardziej znanym takim menad\u017cerem jest z pewno\u015bci\u0105 <em>Puppet<\/em>. Puppet odczytuje konfiguracje serwera zawart\u0105 w tzw. manife\u015bcie. Zazwyczaj jest to plik tekstowy z rozszerzeniem <em>.pp<\/em>.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Pierwszy manifest.<\/span><\/p>\n<p>Manifest to plik zawieraj\u0105cy konfiguracj\u0119 klienta napisan\u0105 w deklaratywnym j\u0119zyku <em>Puppeta<\/em> lub w j\u0119zyku <em>Ruby DSL<\/em> (domain-specific language). G\u0142\u00f3wny plik z manifestem Puppeta to\u00a0 <code>\/etc\/puppetlabs\/code\/environments\/production\/manifests\/site.pp<\/code>. Manifesty <em>Puppeta<\/em> powstaj\u0105 wg schematu:<\/p>\n<pre class=\"lang:sh decode:true\">node 'ppagent1.example.com', 'ppagent2.example.com', ... {\r\n   RESOURCE { NAME1: \r\n       ATTRIBUTE1 =&gt; VALUE1, \r\n   ... \r\n   RESOURCE { NAME_N: \r\n       ATTRIBUTE_N =&gt; VALUE_N, \r\n   }\r\n}\r\n\r\nnode default {\r\n}<\/pre>\n<p>Wszystkie dost\u0119pne rodzaje zasob\u00f3w Puppeta mo\u017cna wylistowa\u0107 po wpisaniu komendy:<\/p>\n<pre class=\"lang:sh decode:true \"># puppet resource --types<\/pre>\n<p>Zasoby zadeklarowane na w\u0119\u017ale o sprecyzowanej nazwie (np. <em>ppagent1.example.com<\/em>) zostan\u0105 utworzone na tym konkretnym w\u0119\u017ale. Zasoby zadeklarowane na w\u0119\u017ale domy\u015blnym (default) zostan\u0105 utworzone na tych wszystkich agentach Puppeta, kt\u00f3re nie zosta\u0142y wprost zadeklarowane wcze\u015bniej (tutaj <em>ppagent1.example.com<\/em>). Np. do pliku <code>site.pp<\/code> wpisujemy<\/p>\n<pre class=\"lang:sh decode:true\">node 'ppagent1.example.com' {\r\n   file { '\/tmp\/hello': \r\n      content =&gt; \"Hello, world\\n\", \r\n      }\r\n\r\nnode default { \r\n}<\/pre>\n<p>Uruchomienie manifestu w trybie <em>master\/agent<\/em>:<\/p>\n<pre class=\"lang:sh decode:true \"># \/opt\/puppetlabs\/bin\/puppet agent --test<\/pre>\n<p>lub po prostu:<\/p>\n<pre class=\"lang:sh decode:true \"># puppet agent --test<\/pre>\n<p>W trybie <em>stand-alone<\/em> manifest wykonywany jest tylko na ho\u015bcie na kt\u00f3rym zosta\u0142 uruchomiony. W tym wypadku manifest mo\u017ce by\u0107 w utworzony w dowolnym katalogu. Uruchamiamy go komend\u0105:<\/p>\n<pre class=\"lang:sh decode:true\"># puppet apply \/path\/to\/site.pp<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Pakiety.<\/span><\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce chcemy uruchomi\u0107 serwer www <em>nginx<\/em> z przyk\u0142adow\u0105 stron\u0105. Najpierw musimy zainstalowa\u0107 <em>epel-relase<\/em> a p\u00f3\u017aniej pakiet <em>nginx. <\/em>Zawarto\u015b\u0107 pliku <code>\/etc\/puppetlabs\/code\/environments\/production\/manifests\/site.pp<\/code>:<\/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 { 'nginx': \r\n     ensure =&gt; installed, \r\n  }\r\n}\r\n\r\nnode default {\r\n}<\/pre>\n<p>Wyra\u017cenie &#8220;-&gt;&#8221; oznacza kolejno\u015b\u0107 wykonywania dzia\u0142a\u0144. Je\u017celi w repozytoriach s\u0105 r\u00f3\u017cne wersje <em>nginx<\/em>, mo\u017cemy wskaza\u0107 kt\u00f3r\u0105 konkretn\u0105 wersj\u0119 chcemy zainstalowa\u0107:<\/p>\n<pre class=\"lang:sh decode:true\">package { 'nginx': \r\n   ensure =&gt; '1.1.19', \r\n}<\/pre>\n<p>Je\u017celi instalujemy <em>nginxa<\/em> to nie potrzebujemy <em>apacha<\/em>, a zatem <em>puppet<\/em> powinien go odinstalowa\u0107 je\u017celi jest ju\u017c w systemie:<\/p>\n<pre class=\"lang:sh decode:true\">package { 'httpd': \r\n   ensure =&gt; absent, \r\n}<\/pre>\n<p>Je\u017celi zale\u017cy nam na tym aby mie\u0107 zainstalowan\u0105 najnowsz\u0105 wersj\u0119 danego pakietu:<\/p>\n<pre class=\"lang:sh decode:true\">package { 'puppet': \r\n   ensure =&gt; latest, \r\n}<\/pre>\n<p>Ale nie zawsze jest to najlepsze rozwi\u0105zanie poniewa\u017c najnowsza wersja danego pakietu mo\u017ce mie\u0107 inn\u0105 konfiguracj\u0119 i system mo\u017ce nie dzia\u0142a\u0107 tak jak sobie tego \u017cyczymy. Taki spos\u00f3b zarz\u0105dzania aktualizacjami systemu mo\u017ce by\u0107 dobrym rozwi\u0105zaniem gdy mamy swoje repozytorium dla serwer\u00f3w i kontrolujemy jakie pakiety s\u0105 w tym repozytorium. A zatem na chwil\u0119 obecn\u0105 manifest wygl\u0105da nast\u0119puj\u0105co:<\/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}\r\n\r\nnode default {\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Us\u0142ugi.<\/span><\/p>\n<p>Po instalacji <em>nginx&#8217;a<\/em> nale\u017ca\u0142oby go jeszcze uruchomi\u0107. W tym celu edytujemy <code>\/etc\/puppetlabs\/code\/environments\/production\/manifests\/site.pp<\/code> .<\/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}\r\n\r\nnode default {\r\n}<\/pre>\n<p>Atrybut <code>require<\/code> okre\u015bla zale\u017cno\u015bci pomi\u0119dzy zasobami. W tym przypadku instalacja nginx&#8217;a mo\u017cliwa jest po odinstalowaniu apacha, a uruchomienie nginxa po jego zainstalowaniu. Wyra\u017cenie <code>Package<\/code> w zapisie <code>require =&gt; Package<\/code> napisane jest z du\u017cej litery poniewa\u017c odnosi si\u0119 do nazwanej instancji zasobu z pakietem. Kod Puppeta wylistowany powy\u017cej 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    before =&gt; Service[nginx],\r\n  }\r\n  service { 'nginx':\r\n    ensure =&gt; running,\r\n  }\r\n}\r\n\r\nnode default {\r\n}<\/pre>\n<p>Czyli pakiet nginx musi zosta\u0107 zainstalowany przed (before) uruchomieniem go.<\/p>\n<p>Na agencie wykonujemy zmodyfikowany manifest:<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppagent puppet]# puppet agent -t\r\n\r\nInfo: Using configured environment 'production'\r\nInfo: Retrieving pluginfacts\r\nInfo: Retrieving plugin\r\nInfo: Loading facts\r\nInfo: Caching catalog for ppagent1.netico.pl\r\nInfo: Applying configuration version '1505502399'\r\nNotice: \/Stage[main]\/Main\/Node[ppagent1.example.com]\/Service[nginx]\/ensure: ensure changed 'stopped' to 'running'\r\nInfo: \/Stage[main]\/Main\/Node[ppagent1.example.com]\/Service[nginx]: Unscheduling refresh on Service[nginx]\r\nNotice: Applied catalog in 1.34 seconds<\/pre>\n<p>Przyk\u0142ad zale\u017cno\u015bci plik\u00f3w jednych od drugich w p\u0119tli:<\/p>\n<pre class=\"lang:sh decode:true\">file { '\/tmp\/file1': \r\n  require =&gt; File['\/tmp\/file2'], \r\n}\r\nfile { '\/tmp\/file2': \r\n  require =&gt; File['\/tmp\/file3'], \r\n}\r\nfile { '\/tmp\/file3': \r\n  require =&gt; File['\/tmp\/file1'], \r\n}<\/pre>\n<p>Dodanie opcji <code>--graph<\/code> podczas uruchamiania manifestu wy\u015bwietli diagram zale\u017cno\u015bci zasob\u00f3w.<\/p>\n<p><em>Puppet<\/em> potrafi kontrolowa\u0107 czy dana us\u0142uga ma by\u0107 uruchamiana w czasie startu systemu. Np. aby wy\u0142\u0105czy\u0107 automatyczne uruchamianie <em>nginxa<\/em> podczas staru systemu w przypadku gdy us\u0142uga jest zarz\u0105dzana przez framework high-availability <em>Heartbeat<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\">service { 'nginx': \r\n   ensure =&gt; running, \r\n   enable =&gt; false, \r\n}<\/pre>\n<p>Automatyczne w\u0142\u0105czenie us\u0142ugi przy starcie systemu wymaga ustawienia atrybutu <code>enable =&gt; true<\/code>.<\/p>\n<p>Skrypt zarz\u0105dzania dan\u0105 us\u0142ug\u0105 powinien obs\u0142ugiwa\u0107 opcj\u0119 status, puppet b\u0119dzie chcia\u0142 j\u0105 u\u017cy\u0107. Je\u017celi skrypt nie ma takiej opcji to j\u0105 wy\u0142\u0105czamy:<\/p>\n<pre class=\"lang:sh decode:true\">service { 'my-service': \r\n   ensure    =&gt; running, \r\n   hasstatus =&gt; false, \r\n}<\/pre>\n<p>Puppet sprawdzi wtedy czy dana us\u0142uga po uruchomieniu jest na li\u015bcie uruchomionych proces\u00f3w systemowych (np. ps). Je\u017celi ta us\u0142uga nie pojawia si\u0119 na li\u015bcie proces\u00f3w systemowych to mo\u017cna zdefiniowa\u0107 w\u0142asny wzorzec szukania procesu:<\/p>\n<pre class=\"lang:sh decode:true\">service { 'my-service': \r\n   ensure    =&gt; running, \r\n   hasstatus =&gt; false, \r\n   pattern   =&gt; 'ruby myservice.rb', \r\n}<\/pre>\n<p>Je\u017celi nie ma \u017cadnej mo\u017cliwo\u015bci na odnalezienie uruchomionego procesu na li\u015bcie proces\u00f3w, mo\u017cna samemu wskaza\u0107 puppetowi komend\u0119, kt\u00f3ra zwr\u00f3ci okre\u015blony status (0 us\u0142uga dzia\u0142a, inna warto\u015b\u0107 us\u0142uga nie dzia\u0142a):<\/p>\n<pre class=\"lang:sh decode:true\">service { 'my-service': \r\n   ensure    =&gt; running, \r\n   hasstatus =&gt; false, \r\n   status    =&gt; 'grep running \/var\/lib\/myservice\/status.txt', \r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Je\u017celi jest potrzeba restartu us\u0142ugi lub wczytania nowych ustawie\u0144 z plik\u00f3w konfiguracyjnych, puppet domy\u015blnie restartuje us\u0142ug\u0119 wy\u0142\u0105czaj\u0105c j\u0105 (stop) i w\u0142\u0105czaj\u0105c (start). Poniewa\u017c wiele us\u0142ug zapewnia opcje restart lub reload a wiele demon\u00f3w przechowuje w pami\u0119ci u\u017cyteczne dane o stanie us\u0142ugi, to lepiej wskaza\u0107 puppetowi jak ma prze\u0142adowa\u0107 lub zrestartowa\u0107 us\u0142ug\u0119:<\/p>\n<pre class=\"lang:sh decode:true\">service { 'ssh': \r\n  ensure  =&gt; running, \r\n  restart =&gt; '\/usr\/sbin\/service ssh reload', \r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">U\u017cytkownicy.<\/span><\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce na maszynie <em>server1<\/em> chcemy za\u0142o\u017cy\u0107 konto dla nowego u\u017cytkownika <em>user1<\/em>. Zmieniamy zatem zawarto\u015b\u0107 pliku <code>site.pp<\/code> :<\/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}\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}<\/pre>\n<p>Atrybut <code>home<\/code> ustawia \u015bcie\u017ck\u0119 do katalogu domowego u\u017cytkownika, katalog ten zostanie utworzony tylko\u00a0 wtedy, gdy zostanie ustawiony r\u00f3wnie\u017c atrybut <code>managehome =&gt; true<\/code>. Chocia\u017c <em>puppet<\/em> potrafi ustawia\u0107 has\u0142a dla kont u\u017cytkownik\u00f3w (atrybut <code>password<\/code>) rekomendowana jest autentykacja przez klucze SSH.<\/p>\n<p>Usuni\u0119cie deklaracji wcze\u015bniej za\u0142o\u017conego konta u\u017cytkownika z manifestu nie spowoduje usuni\u0119cia tego konta. Gdy zajdzie potrzeba usuni\u0119cia konta u\u017cytkownika mo\u017cna to zrobi\u0107 nast\u0119puj\u0105co.:<\/p>\n<pre class=\"lang:sh decode:true\">user { 'user1':\r\n   ensure =&gt; absent,\r\n}<\/pre>\n<p>Katalog domowy u\u017cytkownika <em>user1<\/em> nie zostanie jednak usuni\u0119ty.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Kontrola dost\u0119pu.<\/span><\/p>\n<p>Puppet mo\u017ce zarz\u0105dza\u0107 kluczami publicznymi SSH i autoryzowa\u0107 je dla kont u\u017cytkownik\u00f3w dzi\u0119ki zasobowi <code>ssh_authorized_key<\/code>. Je\u017celi mamy ju\u017c klucz publiczny to mo\u017cemy go wykorzysta\u0107:<\/p>\n<pre class=\"lang:sh decode:true\"># cat ~\/.ssh\/id_rsa.pub\r\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA3ATqENg+GWACa2BzeqTdGnJhNoBer8x6pfWkzNzeM8Zx7\/2Tf2pl7kHdbsiTXEUawqzXZQtZzt\/j3Oya+PZjcRpWNRzprSmd2UxEEPTqDw9LqY5S2B8og\/NyzWaIYPsKoatcgC7VgYHplcTbzEhGu8BsoEVBGYu3IRy5RkAcZik=<\/pre>\n<p>Je\u017celi nie to nale\u017cy go wygenerowa\u0107:<\/p>\n<pre class=\"lang:sh decode:true\"># ssh-keygen\r\nGenerating public\/private rsa key pair.\r\nEnter passphrase (empty for no passphrase):\r\nEnter same passphrase again:\r\nYour identification has been saved in user1.\r\nYour public key has been saved in id_rsa.pub.\r\nThe key fingerprint is:\r\n40:83:af:73:1d:ac:8e:28:12:16:6a:9e:6b:59:1e:29 root@ppmaster.netico.pl\r\nThe key's randomart image is:\r\n+--[ RSA 2048]----+\r\n| .o |\r\n| .. . |\r\n| ... |\r\n| . ..o |\r\n|. . .. oS. |\r\n|oE +o o . |\r\n|+.*..= |\r\n|o=... . |\r\n|oo. |\r\n+-----------------+<\/pre>\n<p>Teraz modyfikujemy zawarto\u015b\u0107 pliku <code>site.pp<\/code> :<\/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}\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>Uruchomienie manifestu <em>puppeta<\/em> na agencie <em>ppagent1.example.com<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\"># puppet -t agent<\/pre>\n<p>Klucz publiczny znajdzie si\u0119 teraz na li\u015bcie kluczy autoryzowanych dla u\u017cytkownika <em>user1<\/em>:<\/p>\n<pre class=\"lang:sh decode:true \"># cat \/home\/user1\/.ssh\/authorized_keys\r\n# HEADER: This file was autogenerated at 2017-09-19 15:08:58 +0200\r\n# HEADER: by puppet. While it can still be managed manually, it\r\n# HEADER: is definitely not recommended.\r\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA3ATqENg+GWACa2BzeqTdGnJhNoBer8x6pfWkzNzeM8Zx7\/2Tf2pl7kHdbsiTXEUawqzXZQtZzt\/j3Oya+PZjcRpWNRzprSmd2UxEEPTqDw9LqY5S2B8og\/NyzWaIYPsKoatcgC7VgYHplcTbzEhGu8BsoEVBGYu3IRy5RkAcZik= user1<\/pre>\n<p>My jako root z hosta <em>ppmaster.example.com<\/em> b\u0119dziemy mogli si\u0119 logowa\u0107 bez has\u0142a na konto <em>user1<\/em> na hosta <em>ppagent1.example.com<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\">[root@ppmaster manifests]# ssh user1@ppagent1.netico.pl\r\nLast login: Tue Sep 19 15:09:21 2017 from ppmaster<\/pre>\n<p>&nbsp;<\/p>\n<p>Je\u017celi chcemy wygenerowa\u0107 klucz dla innego u\u017cytkownika ni\u017c aktualnie zalogowany:<\/p>\n<pre class=\"lang:sh decode:true\"># cd \/home\/user1\/.ssh\r\n# ssh-keygen -f id_rsa\r\nGenerating public\/private rsa key pair.\r\nEnter passphrase (empty for no passphrase):\r\nEnter same passphrase again:\r\nYour identification has been saved in user1.\r\nYour public key has been saved in user1.pub.\r\nThe key fingerprint is:\r\n40:83:af:73:1d:ac:8e:28:12:16:6a:9e:6b:59:1e:29 root@ppmaster.netico.pl\r\nThe key's randomart image is:\r\n+--[ RSA 2048]----+\r\n| .o |\r\n| .. . |\r\n| ... |\r\n| . ..o |\r\n|. . .. oS. |\r\n|oE +o o . |\r\n|+.*..= |\r\n|o=... . |\r\n|oo. |\r\n+-----------------+<\/pre>\n<p>Odczyt klucza publicznego:<\/p>\n<pre class=\"lang:sh decode:true\"># cat \/home\/user1\/.ssh\/id_rsa.pub\r\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDozMFm++tr0UFUeHZTT3vqqygsnMcdkIiDDCYQz3140lOjx3kts4lPF41gVU1V6cVoY7yJ3XVMUguEHOEwoMuvUudSurN0ufIxh5H8ZVott27g7aJZGwUdEkdPNX\/U1G+GnQ0dU\/RtPw+oTIaXlnMEG6T9ECmZP8ON5n3uvlpsH\/9t6U19B4t2\/0oPIfu5H+5TgNDbweceun5X39XZm\/PqMOy7A0Ynuh\/4g9iA4VIo2YUrQV7kA2lK6tWQZ1SoJnrMr21NUq8L4fP1KclGcZz2dmRbDSDJNGLPlKjZtwXK+cLGQzvBUpqFjGG8FDx5Lz9AhxhVg\/MiZfXNq1H0mw\/n root@example.com<\/pre>\n<p>Korzystaj\u0105c z tak wygenerowanego klucza b\u0119dziemy mogli logowa\u0107 si\u0119 bez has\u0142a z konta <em>user1@ppmaster<\/em> na konto <em>user1@ppagent1<\/em>.<\/p>\n<pre class=\"lang:sh decode:true\">[user1@ppmaster manifests]# ssh user1@ppagent1.netico.pl\r\nLast login: Tue Sep 19 15:00:20 2017 from ppmaster<\/pre>\n<p>&nbsp;<\/p>\n<p>Je\u017celi natomiast zajdzie potrzeba zablokowania u\u017cytkownikowi <em>user1<\/em> logowania to mo\u017cna tymczasowo usun\u0105\u0107 jego klucz SSH z Puppeta:<\/p>\n<pre class=\"lang:sh decode:true\">ssh_authorized_key { 'user1': \r\n   user =&gt; 'user1', \r\n   type =&gt; 'rsa', \r\n   key =&gt; '', \r\n}<\/pre>\n<p>Je\u017celi natomiast u\u017cytkownik <em>user1<\/em> mia\u0142 ustawion\u0105 kontrol\u0119 dost\u0119pu na podstawie has\u0142a a nie klucza ssh (co nie jest rekomendowane) to mo\u017cemy mu zablokowa\u0107 mo\u017cliwo\u015b\u0107 logowania do systemu ustawiaj\u0105c atrybut <code>password =&gt; '*'<\/code> :<\/p>\n<pre class=\"lang:sh decode:true\">   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      password   =&gt; '*',\r\n  \r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Zadania.<\/span><\/p>\n<p><em>Puppet<\/em> daje mo\u017cliwo\u015b\u0107 wykonywania okre\u015blonych komend bezpo\u015brednio przy wykorzystaniu zasobu <code>exec,<\/code> np:<code><\/code><\/p>\n<pre class=\"lang:sh decode:true\">  exec { 'My command':\r\n    command =&gt; '\/bin\/echo I ran this command on `\/bin\/date` &gt;\/tmp\/\r\n    command.output.txt',\r\n  }\r\n<\/pre>\n<p>Wymagane jest podanie przez nas pe\u0142nej \u015bcie\u017cki do pliku ale mo\u017cemy tak\u017ce dostarczy\u0107 list\u0119 takich \u015bcie\u017cek atrybutem <code>path<\/code>.<\/p>\n<pre class=\"lang:sh decode:true\">  exec { 'My command':\r\n    command =&gt; 'echo I ran this command on `date` &gt;\/tmp\/\r\n    command.output.txt',\r\n    path =&gt; ['\/bin', '\/usr\/bin'],\r\n  }<\/pre>\n<p>Mo\u017cliwe jest tak\u017ce okre\u015blenie domy\u015blnej \u015bcie\u017cki dla wszystkich zasob\u00f3w <code>exec<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">Exec {\r\n  path =&gt; ['\/bin', '\/usr\/bin'],\r\n}<\/pre>\n<p>Po takiej deklaracji mo\u017cliwe jest podawania komend bez pe\u0142nej \u015bcie\u017cki:<\/p>\n<pre class=\"lang:sh decode:true\">  exec { 'My command':\r\n    command =&gt; 'echo I ran this command on `date` &gt;\/tmp\/\r\n    command.output.txt',\r\n  }<\/pre>\n<p>Zas\u00f3b <code>exec<\/code> spowoduje uruchomienie jednak komendy za ka\u017cdym razem gdy uruchomiony zostanie na agencie manifest <em>Puppeta<\/em>. Je\u017celi natomiast chcemy dan\u0105 komend\u0119 uruchomi\u0107 tylko jeden raz to robimy to w spos\u00f3b, kt\u00f3ry ilustruje przek\u0142ad poni\u017cej.<\/p>\n<pre class=\"lang:sh decode:true\">exec { 'Download private key for John':\r\n  cwd     =&gt; '\/home\/john\/.ssh',\r\n  command =&gt; '\/usr\/bin\/wget http:\/\/example.com\/files\/id_rsa',\r\n  creates =&gt; '\/home\/john\/.ssh\/id_rsa',\r\n}<\/pre>\n<p>Atrybut <code>cwd\u00a0<\/code> zmienia bie\u017c\u0105cy katalog. <em>Puppet<\/em> sprawdza czy istnieje plik okre\u015blony przez atrybut <code>creates<\/code>. Je\u017celi nie istnieje to jest uruchamiany atrybut <code>command<\/code>. Je\u017celi istnieje to <em>Puppet<\/em> nie robi nic.<\/p>\n<p>Mo\u017cna to samo osi\u0105gn\u0105\u0107 atrybutem <code>unless<\/code> lub <code>onlyif<\/code>.<\/p>\n<pre class=\"lang:sh decode:true\">exec { 'Download private key for John':\r\n  cwd     =&gt; '\/home\/john\/.ssh',\r\n  command =&gt; '\/usr\/bin\/wget http:\/\/example.com\/files\/id_rsa',\r\n  unless =&gt; '\/usr\/bin\/find . -name 'id_rsa',\r\n}<\/pre>\n<p>Komendy mo\u017cna tak\u017ce wykonywa\u0107 automatycznie je\u017celi zmieni si\u0119 zawarto\u015b\u0107 jakiego\u015b pliku.<\/p>\n<pre class=\"lang:sh decode:true\">exec { 'icinga-config-check':\r\n  command =&gt; '\/usr\/sbin\/icinga -v \/etc\/icinga\/icinga.cfg &amp;&amp; \/usr\/\r\nsbin\/service icinga restart',\r\n  refreshonly =&gt; true,\r\n  subscribe =&gt; File['\/etc\/icinga\/icinga.cfg'],\r\n  }<\/pre>\n<p>Komendy mo\u017cna tak\u017ce wykonywa\u0107 sekwencyjnie. Odpowiednikiem zapisu:<\/p>\n<pre class=\"lang:sh decode:true\"># \/usr\/sbin\/icinga -v \/etc\/icinga\/icinga.cfg &amp;&amp; \/usr\/sbin\/service icinga\r\nrestart<\/pre>\n<p>jest zapis:<\/p>\n<pre class=\"lang:sh decode:true\">exec { 'command-1':\r\n  command =&gt; '\/bin\/echo Step 1',\r\n  }\r\nexec { 'command-2':\r\n  command =&gt; '\/bin\/echo Step 2',\r\n  require =&gt; Exec['command-1'],\r\n  }\r\nexec { 'command-3':\r\n  command =&gt; '\/bin\/echo Step 3',\r\n  require =&gt; Exec['command-2'],\r\n  }<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Cron.<\/span><\/p>\n<p>Je\u017celi istnieje potrzeba wykonywania pewnych czynno\u015bci okresowo to realizujemy to przy pomocy <em>crona<\/em>. <em>Puppet<\/em> mo\u017ce r\u00f3wnie\u017c zarz\u0105dza\u0107 <em>cronem<\/em> na naszych agentach.<\/p>\n<pre class=\"lang:sh decode:true\">cron { 'Files backup':\r\n  command =&gt; '\/usr\/bin\/rsync -az \/path\/from\/ \/path\/to\/',\r\n  hour    =&gt; '04',\r\n  minute  =&gt; '00',\r\n}<\/pre>\n<p>Je\u017celi pozosta\u0142e argumenty <em>crona<\/em> takie jak <code>month<\/code>, <code>day<\/code>, <code>weekday<\/code> nie zosta\u0142y podane tzn. , \u017ce przyjmuj\u0105 one warto\u015b\u0107 domy\u015bln\u0105 *. Domy\u015blnie zadania <em>crona<\/em> uruchamia root, ale mo\u017cemy je uruchamia\u0107 tak\u017ce jako inny u\u017cytkownik dzi\u0119ki atrybutowi <code>user<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">cron { 'Files backup':\r\n  command =&gt; '\/usr\/bin\/rsync -az \/path\/from\/ \/path\/to\/',\r\n  user    =&gt; 'user1',\r\n  hour    =&gt; '04',\r\n  minute  =&gt; '00',\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Sudo (OLD).<\/span><\/p>\n<p>Je\u017celi chcemy aby aby zwykli u\u017cytkownicy mieli jakie\u015b uprawnienia superu\u017cytkownika root to wykonujemy poni\u017csze kroki.<\/p>\n<p>Tworzymy katalogi dla konfiguracji <code>\/etc\/sudoers<\/code>:<\/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\/sudoers\/manifests\/init.pp<\/code> o tre\u015bci:<\/p>\n<pre class=\"lang:sh decode:true\"># Manage the sudoers file\r\nclass sudoers \r\n{\r\n   file { '\/etc\/sudoers':\r\n      source =&gt; 'puppet:\/\/\/puppet\/modules\/sudoers\/sudoers',\r\n      mode  =&gt; '0440',\r\n      owner =&gt; 'root',\r\n      group =&gt; 'root',\r\n   }\r\n}\r\n<\/pre>\n<p>Zak\u0142adamy plik <code>\/puppet\/modules\/sudoers\/files\/sudoers<\/code> z zawarto\u015bci\u0105:<\/p>\n<pre class=\"lang:sh decode:true\"> # User privilege specification\r\nroot  ALL = (ALL) ALL\r\nuser1 ALL = (ALL) NOPASSWD:ALL\r\nuser2 ALL = (ALL) NOPASSWD: \/bin\/ls<\/pre>\n<p>Sprawdzamy poprawno\u015b\u0107 pliku:<\/p>\n<pre class=\"lang:sh decode:true \"># visudo -c -f \/puppet\/modules\/sudoers\/files\/sudoers\r\nmodules\/sudoers\/files\/sudoers: parsed OK<\/pre>\n<p>Do definicji w\u0119z\u0142a <em>server1<\/em> dodajemy wczytywanie nowej klasy <em>sudoers<\/em>:<\/p>\n<pre class=\"lang:sh decode:true\">node 'server1' \r\n{ \r\n   include nginx \r\n   include ssh\r\n   include sudoers\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<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Za\u0142\u00f3\u017cmy, \u017ce mamy do postawienia kilkaset wirtualnych serwer\u00f3w z okre\u015blonym oprogramowaniem i konfiguracj\u0105. Je\u017celi chcieliby\u015bmy wykona\u0107 to zadanie r\u0119cznie by\u0142oby to bardzo pracoch\u0142onne. W instalacji wirtualnych maszyn pomo\u017ce nam z pewno\u015bci\u0105 Kickstart, a z konfiguracj\u0105 tych maszyn mo\u017ce nam pom\u00f3c dowolny menad\u017cer konfiguracji. Najbardziej znanym takim menad\u017cerem jest z pewno\u015bci\u0105 Puppet. Puppet odczytuje konfiguracje serwera &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/miro.borodziuk.eu\/index.php\/2017\/08\/16\/puppet-standalone\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;J\u0119zyk DSL Puppeta cz.1&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":1754,"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\/1888"}],"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=1888"}],"version-history":[{"count":33,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/1888\/revisions"}],"predecessor-version":[{"id":1977,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/1888\/revisions\/1977"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media\/1754"}],"wp:attachment":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media?parent=1888"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/categories?post=1888"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/tags?post=1888"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}