Palvelinten hallinta - Harjoitus 4
==============

*Disclaimer:*
--------------

Tämä harjoitus on tehty osana Haaga-Helian Tietojenkäsittelyn koulutusohjelman kurssia [Palvelinten hallinta (ICT4TN022, kevät 2018)](http://www.haaga-helia.fi/fi/opinto-opas/opintojaksokuvaukset/ICT4TN022). Kurssin pitäjänä toimii [Tero Karvinen](http://terokarvinen.com/), joka on määritellyt tämän harjoituksen tehtävänkuvaukset. Tehtävien vastaukset ovat Pekka Heleniuksen (allekirjoittanut) tuottamia.

*SISÄLLYSLUETTELO*
--------------

- [Harjoituksen esivaatimus - kahden minion-koneen asentaminen Vagrantilla](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h4.md#harjoituksen-esivaatimus---kahden-minion-koneen-asentaminen-vagrantilla)

- [b) Tee kahdella orjalla esimerkki, jossa orjat saavat eri muuttujan pilarista. Tarkista ‘pillars.items’, että kummalekin orjalle mene eri tieto. Tee jokin muu kuin tunnilla tehty sshd-esimerkki.](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h4.md#b-tee-kahdella-orjalla-esimerkki-jossa-orjat-saavat-eri-muuttujan-pilarista-tarkista-pillarsitems-ett%C3%A4-kummalekin-orjalle-mene-eri-tieto-tee-jokin-muu-kuin-tunnilla-tehty-sshd-esimerkki)

- [c) Tee kahdella orjalla esimerkki, jossa toinen orja saa muuttujan pilarista ja toinen käyttää oletusarvoa (pillar.get). Tee jokin muu kuin tunnilla tehty sshd-esimerkki.](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h4.md#c-tee-kahdella-orjalla-esimerkki-jossa-toinen-orja-saa-muuttujan-pilarista-ja-toinen-k%C3%A4ytt%C3%A4%C3%A4-oletusarvoa-pillarget-tee-jokin-muu-kuin-tunnilla-tehty-sshd-esimerkki)

Harjoituksen esivaatimuksena on käyttää useampaa Minion-konetta Salt:lla. Useamman Salt-minionin luomiseen on monta eri tapaa, kuten

- 1) luodaan jokaiselle minionille oma virtuaalikoneensa (Oracle VirtualBox, VMWare, Vagrant...), jotka kykenevät muodostamaan yhteyden Master-koneeseen

- 2) luodaan jokaiselle minionille oma konttinsa (docker, systemd-nspawn), jotka kykenevät muodostamaan yhteyden Master-koneeseen

- 3) käytetään olemassa olevia virtuaalikoneita, jotka pyörivät esimerkiksi palvelinsaleissa

- 4) luodaan joko fyysiselle tai virtuaaliselle tietokoneelle useampi minion-konfiguraatio omine ID:ineen (huonoin!)

Toteutetaan vaihtoehto 1) Vagrantilla.

Harjoituksen esivaatimus - kahden minion-koneen asentaminen Vagrantilla
--------------

Toteutetaan minion-koneet [Vagrant-virtualisoinnilla](https://en.wikipedia.org/wiki/Vagrant_(software)).

Tässä vaiheessa oletetaan, että koneelta löytyy Salt-master jo valmiina (ks. mm. [harjoitus 1](https://raw.githubusercontent.com/Fincer/central-management-of-multiple-servers/master/h1.md)).

Asennetaan vagrant

```
sudo apt-get -y install vagrant
```

Tietokoneelta löytyy ennestään _virtualbox_ asennettuna, mutta se voidaan asentaa myös:

```
sudo apt-get -y install virtualbox
```

Vagrant käyttää laatikoita (boxes) virtualisoitujen ympäristöjen toteuttamisessa. Käytän harjoituksessa laatikkoa [debian/jessie64](https://app.vagrantup.com/debian/boxes/jessie64). Tässä täytyy olla tarkkana, ettei käytettyjen Salt:ien versiot ja API:t rikkoonnu! Tuotantoympäristössä nämä on tarkistettava ja katsottava huolella!

Luodaan kaksi Salt minion -konetta ajamalla seuraava Vagrantfile Master-koneen myöhemmin valittavassa alihakemistossa:

[Vagrantfile - Multiple Salt minions](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/scripts/vagrant_salt-minions/Vagrantfile)

**HUOM!** Vagrant-ratkaisu ei toimi hyvin jo-virtualisoiduissa työympäristöissä, eli Vagrantia tulisi ajaa "fyysisellä" koneella.

Ladataan yllä mainittu Vagrantfile master-koneen alihakemistoon /srv/salt/vagrant_minions:

```
sudo mkdir -p /srv/salt/vagrant_minions
sudo wget https://raw.githubusercontent.com/Fincer/central-management-of-multiple-servers/master/scripts/vagrant_salt-minions/Vagrantfile -O /srv/salt/vagrant_minions/Vagrantfile
```

Ladatussa Vagrantfile:ssä on jo ennestään määritetty luotavaksi kaksi Salt-minionia: minion_1 ja minion_2 laatikkotemplatella debian/jessie64.

**HUOM!** Monet _vagrant_ -komennot on sidottu työhakemistoon. Ennestään luodut virtuaalikoneet  tulee ne tuhota siitä hakemistosta käsin, jossa koneet on luotu (ja siis jossa Vagrantfile sijaitsee). Vagrant luo tähän hakemistoon piilohakemiston _.vagrant/machines_, johon koneet on luotu.

Annetaan master-koneen normaalille ylläpitäjälle (UID: 1000, GID: 1000 ja kuuluu sudo-ryhmään) omistusoikeus kansioon /srv/salt/vagrant_minions:

```
sudo chown 1000:1000 -R /srv/salt/vagrant_minions
```

Luodaan tällä käyttäjällä tuohon hakemistoon viittaava symbolinen linkki kys. käyttäjän kotihakemistoon:

```
ln -s /srv/salt/vagrant_minions $HOME/vagrant-minions
```

**HUOM!** Edellä olevaa ei ole pakko tehdä, ja se on täysin vapaaehtoista. Halusin tehdä sen selkeyden vuoksi.

Ajetaan ladattu Vagrantfile:

```
cd $HOME/vagrant-minions
vagrant up
```

Testataan laatikoiden minion_1 ja minion_2 SSH-toimivuus ajamalla:

```
vagrant ssh minion_1
vagrant ssh minion_2
```

![vagrant-connection-test](https://raw.githubusercontent.com/Fincer/central-management-of-multiple-servers/master/images/vagrant-connection-test.png)

Hyväksytään nämä minion-koneet masterilla:

```
[23/04/2018 19:24:57 - fincer: vagrant ]$ sudo salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
minion_1
minion_2
Proceed? [n/Y] y
Key for minion minion_1 accepted.
Key for minion minion_2 accepted.
```

**b)** Tee kahdella orjalla esimerkki, jossa orjat saavat eri muuttujan pilarista. Tarkista ‘pillars.items’, että kummalekin orjalle mene eri tieto. Tee jokin muu kuin tunnilla tehty sshd-esimerkki.
--------------

**Vastaus:**

Ajetaan root-käyttäjänä (sudo-komento) seuraava shell-skripti master-koneella:

[Pekka Helenius - salt_pillar_sample.sh](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/scripts/salt_pillar_sample.sh)

Masterilta saatu output:

```
[23/04/2018 19:41:45 - fincer: vagrant ]$ sudo sh pillar_sample.sh
base:
  'minion_1':
    - minion-1
  'minion_2':
    - minion-2
test_variable: 'secret like coffee shop wants to say hello to the world'
test_variable: 'hidden miniart: superman vs. hulk figures'
This is my pillarfile which has the following content:

{{ pillar['test_variable'] }}
pillar_file:
  file.managed:
    - user: 1000
    - group: 1000
    - name: /tmp/pillarfile_for_{{ grains['id'] }}
    - source: salt://files/pillarfile
    - makedirs: True
    - template: jinja

minion_2:
    True
minion_1:
    True

**Salt -- pillar.items output**

minion_2:
    ----------
    test_variable:
        hidden miniart: superman vs. hulk figures
minion_1:
    ----------
    test_variable:
        secret like coffee shop wants to say hello to the world

**Salt -- state.apply output**

minion_1:
----------
          ID: pillar_file
    Function: file.managed
        Name: /tmp/pillarfile_for_minion_1
      Result: True
     Comment: File /tmp/pillarfile_for_minion_1 is in the correct state
     Started: 16:42:18.786164
    Duration: 54.806 ms
     Changes:   

Summary for minion_1                                                                                                                                       
------------                                                                                                                                               
Succeeded: 1
Failed:    0
------------
Total states run:     1
Total run time:  54.806 ms
minion_2:
----------
          ID: pillar_file
    Function: file.managed
        Name: /tmp/pillarfile_for_minion_2
      Result: True
     Comment: File /tmp/pillarfile_for_minion_2 is in the correct state
     Started: 16:42:18.886370
    Duration: 57.26 ms
     Changes:   

Summary for minion_2
------------
Succeeded: 1
Failed:    0
------------
Total states run:     1
Total run time:  57.260 ms

**Salt -- get file output with head command**

minion_2:
    This is my pillarfile which has the following content:
    
    hidden miniart: superman vs. hulk figures
minion_1:
    This is my pillarfile which has the following content:
    
    secret like coffee shop wants to say hello to the world
```

**c)** Tee kahdella orjalla esimerkki, jossa toinen orja saa muuttujan pilarista ja toinen käyttää oletusarvoa (pillar.get). Tee jokin muu kuin tunnilla tehty sshd-esimerkki.
--------------

**Vastaus:**

Asennetaan molemmille orjille Apache HTTP daemon seuraavaa shell-skriptiä käyttäen:

[salt_pillar_apache_sample.sh](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/scripts/salt_pillar_apache_sample.sh)

Masterilta saatu output:

```
[24/04/2018 01:57:10 - fincer: vagrant ]$ sudo sh apache_sample.sh 
{% if grains['id'] == 'minion_2' %}
site_data: '{{ salt['cmd.run']('uname -a') }}'
{% endif %}
<VirtualHost *:80>
    ServerName {{ servername }}
    ServerAlias {{ serveralias }}
    ServerAdmin webmaster@localhost
    DocumentRoot {{ ('/var/www/html/' + grains['id'] + '/') }}
    ErrorLog /error.log
    CustomLog /access.log combined
</VirtualHost>
{{ pillar.get('site_data','Nothing interesting here') }}

{% set servername = grains['os'].lower() + '.' + grains['id'] + '.com' %}
{% set serveralias = 'www.' + grains['os'].lower() + '.' + grains['id'] + '.com' %}

apache_install:
  pkg.installed:
    - pkgs:
      - apache2
      - curl

sample_page_conf:
  file.managed:
    - name: /etc/apache2/sites-available/{{ grains['id'] }}.conf
    - source: salt://apache/samplesite.conf
    - mode: 0644
    - user: root
    - group: root
    - template: jinja
    - context:
      servername: {{ servername }}
      serveralias: {{ serveralias }}
    - require:
      - pkg: apache_install

enable_sample_page:
  cmd.run:
    - name: 'a2ensite {{ grains['id'] }}.conf'
    - require:
      - file: sample_page_conf
      
sample_page_content:
  file.managed:
    - mode: 0644
    - user: root
    - group: root
    - makedirs: True
    - template: jinja
    - name: {{ ('/var/www/html/' + grains['id'] + '/index.html') }}
    - source: salt://apache/sampleindex.html
    - require:
      - cmd: enable_sample_page

add_vhost_domain:
  file.append:
    - name: /etc/hosts
    - text: 127.0.0.1 {{ servername }}
    - require:
      - file: sample_page_content
      
restart_httpd:
  service.running:
    - name: apache2.service
    - watch:
      - file: add_vhost_domain
      - cmd: enable_sample_page

test_page:
  cmd.run:
    - name: 'curl -s {{ servername }}'
    - require:
      - service: restart_httpd


**Salt -- pillar.items output**

minion_1:
    ----------
    test_variable:
        secret like coffee shop wants to say hello to the world
minion_2:
    ----------
    site_data:
        Linux fincer-laptop 4.15.10-1-ARCH #1 SMP PREEMPT Thu Mar 15 12:24:34 UTC 2018 x86_64 GNU/Linux
    test_variable:
        hidden miniart: superman vs. hulk figures

**Salt -- state.apply output**

minion_1:
----------
          ID: apache_install
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 22:59:25.325084
    Duration: 273.26 ms
     Changes:   
----------
          ID: sample_page_conf
    Function: file.managed
        Name: /etc/apache2/sites-available/minion_1.conf
      Result: True
     Comment: File /etc/apache2/sites-available/minion_1.conf is in the correct state
     Started: 22:59:25.599368
    Duration: 51.619 ms
     Changes:   
----------
          ID: enable_sample_page
    Function: cmd.run
        Name: a2ensite minion_1.conf
      Result: True
     Comment: Command "a2ensite minion_1.conf" run
     Started: 22:59:25.651513
    Duration: 20.174 ms
     Changes:   
              ----------                                                                                                                         
              pid:
                  13401
              retcode:
                  0
              stderr:
              stdout:
                  Site minion_1 already enabled
----------
          ID: sample_page_content
    Function: file.managed
        Name: /var/www/html/minion_1/index.html
      Result: True
     Comment: File /var/www/html/minion_1/index.html is in the correct state
     Started: 22:59:25.671991
    Duration: 9.937 ms
     Changes:   
----------
          ID: add_vhost_domain
    Function: file.append
        Name: /etc/hosts
      Result: True
     Comment: File /etc/hosts is in correct state
     Started: 22:59:25.682126
    Duration: 1.011 ms
     Changes:   
----------
          ID: restart_httpd
    Function: service.running
        Name: apache2.service
      Result: True
     Comment: Service restarted
     Started: 22:59:25.697483
    Duration: 2145.224 ms
     Changes:   
              ----------                                                                                                                         
              apache2.service:
                  True
----------
          ID: test_page
    Function: cmd.run
        Name: curl -s ubuntu.minion_1.com
      Result: True
     Comment: Command "curl -s ubuntu.minion_1.com" run
     Started: 22:59:27.842981
    Duration: 9.994 ms
     Changes:   
              ----------                                                                                                                         
              pid:
                  13523
              retcode:
                  0
              stderr:
              stdout:
                  Nothing interesting here

Summary for minion_1                                                                                                                             
------------                                                                                                                                     
Succeeded: 7 (changed=3)
Failed:    0
------------
Total states run:     7                                                                                                                          
Total run time:   2.511 s
minion_2:
----------
          ID: apache_install
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 22:59:25.453349
    Duration: 273.908 ms
     Changes:   
----------
          ID: sample_page_conf
    Function: file.managed
        Name: /etc/apache2/sites-available/minion_2.conf
      Result: True
     Comment: File /etc/apache2/sites-available/minion_2.conf is in the correct state
     Started: 22:59:25.728257
    Duration: 10.512 ms
     Changes:   
----------
          ID: enable_sample_page
    Function: cmd.run
        Name: a2ensite minion_2.conf
      Result: True
     Comment: Command "a2ensite minion_2.conf" run
     Started: 22:59:25.739209
    Duration: 18.428 ms
     Changes:   
              ----------                                                                                                                         
              pid:
                  13160
              retcode:
                  0
              stderr:
              stdout:
                  Site minion_2 already enabled
----------
          ID: sample_page_content
    Function: file.managed
        Name: /var/www/html/minion_2/index.html
      Result: True
     Comment: File /var/www/html/minion_2/index.html is in the correct state
     Started: 22:59:25.757909
    Duration: 8.736 ms
     Changes:   
----------
          ID: add_vhost_domain
    Function: file.append
        Name: /etc/hosts
      Result: True
     Comment: File /etc/hosts is in correct state
     Started: 22:59:25.766840
    Duration: 0.933 ms
     Changes:   
----------
          ID: restart_httpd
    Function: service.running
        Name: apache2.service
      Result: True
     Comment: Service restarted
     Started: 22:59:25.779507
    Duration: 2102.595 ms
     Changes:   
              ----------
              apache2.service:
                  True
----------
          ID: test_page
    Function: cmd.run
        Name: curl -s ubuntu.minion_2.com
      Result: True
     Comment: Command "curl -s ubuntu.minion_2.com" run
     Started: 22:59:27.882439
    Duration: 11.578 ms
     Changes:   
              ----------
              pid:
                  13282
              retcode:
                  0
              stderr:
              stdout:
                  Linux fincer-laptop 4.15.10-1-ARCH #1 SMP PREEMPT Thu Mar 15 12:24:34 UTC 2018 x86_64 GNU/Linux

Summary for minion_2
------------
Succeeded: 7 (changed=3)
Failed:    0
------------
Total states run:     7
Total run time:   2.427 s
```

Luotujen HTML-sivustojen sisältö:

```
[24/04/2018 01:59:28 - fincer: vagrant ]$ sudo salt 'minion_1' cmd.run 'curl -s ubuntu.minion_1.com'
minion_1:
    Nothing interesting here
[24/04/2018 02:00:47 - fincer: vagrant ]$ sudo salt 'minion_2' cmd.run 'curl -s ubuntu.minion_2.com'
minion_2:
    Linux fincer-laptop 4.15.10-1-ARCH #1 SMP PREEMPT Thu Mar 15 12:24:34 UTC 2018 x86_64 GNU/Linux
```
