# Laboratorium 3 SLCD
### Orkiestracja w platformie OpenStack
## Autorzy:
* Wawrzyńczak Michał
* Gryka Paweł
-----------------------
## Spis treści
* [Wstęp](#Wstęp)
* [4. Część 1: OpenStack Dashboard](#4-Część-1:-OpenStack-Dashboard)
+ [4.2 Tworzenie sieci użytkownika](#42-Tworzenie-sieci-użytkownika)
+ [4.3 Udrożnienie komunikacji przez sieć zewnętrzną](#43-Udrożenienie-komunikacji-przez-sieć-zewnętrzną)
+ [4.4 Utworzenie obrazu maszyny wirtualnej](#44-Utworzenie-obrazu-maszyny-wirtualnej)
+ [4.5 Uruchomienie maszyny wirtualnej](#45-Uruchomienie-maszyny-wirtualnej)
* [5. Część 2: OpenStack Heat](#5-Część-2:-OpenStack-Heat)
+ [5.7 Utworzenie stosu](#57-Utworzenie-stosu)
+ [5.8 Deklaratywna modyfikacja stosu](#58-Deklaratywna-modyfikacja-stosu)
+ [5.9 Zadania dodatkowe/nieobowiązkowe](#59-Zadania-dodatkowe-nieobowiązkowe)
* [6 Podsumowanie laboratorium](#6-Podsumowanie-laboratorium)
* [Zmodyfikowany template na potrzeby zadań dodatkowych](#Zmodyfikowany-template-na-potrzeby-zadan-dodatkowych)
## Wstęp
Celem ćwiczenia jest opanowanie podstawowych zasad wykorzystania orkiestratora Heat platformy OpenStack. W wyniku realizacji zadania zapoznamy się z zasadami deklaratywnego podejścia do automatyzacji procesów zarządzania usługami teleinformatycznymi.
## 4. Część 1: OpenStack Dashboard
### 4.2 Tworzenie sieci użytkownika
W tym kroku stworzona została sieć o nazwie `tenant-bejbiszarki` z adresami `192.168.11.0/28`. Adres gatewaya został ustalony `192.168.11.1`.

### 4.3 Udrożenienie komunikacji przez sieć zewnętrzną
Utworzony został router `router-bejbiszarki` external network zdefiniowana jako istniejąca sieć external. Dodano również interfejs z wcześniej utworzoną podsiecią prywatną. W wyniku tych działań udało się uzyskać wymaganą topologię sieci. Sieć `external` połączyła się z siecią `tenant-bejbisharki` Poniżej znajdują się screeny z wyświetlonym opisem routera.
# POLECENIA DO SPRAWOZDANIA
1. Przedstawić zrzut całego panelu Topology z topologią uzyskanej sieci i wyświetlonym opisem routera w formie jak na poniższym rysunku (fragment panelu Topology).

### 4.4 Utworzenie obrazu maszyny wirtualnej
Obraz maszyny został pobrany na komputer jednego ze studentów. Następnie załadowaliśmy go na serwer OpenStack. W OpenStack został stworzony nowy image z unikatową nazwą `cirros-bejbiszarki-image`. Poniżej screen przedstawiający poprawne dodanie image'u na serwer OpenStack


### 4.5 Uruchomienie maszyny wirtualnej
Stworzyliśmy instancję z systemem `cirros`. Instancji nadana została nazwa `instance_bejbiszarki_1`. Instancja została prawidłowo stworzona co widać na poniższym zrzucie ekranu.


Kolejnym etapem było dodanie `FloatingIp`. Pozwala to na zmapowanie adresu z sieci external do adresu konkretnej instancji. Na poniższym screenie widać, że floating ip address został skojarzony z adresem stworzonej wcześniej instancji maszyny `cirros`.

Po wyłączeniu opcji `Port security` w `Security Groups` instancja była dostępna z sieci spoza DC.
# POLECENIA DO SPRAWOZDANIA - OBOWIĄZKOWE
1. Przedstawić zrzut całego panelu Topology z topologią uzyskanej sieci i wyświetlonym opisem utworzonej maszyny wirtualnej w formie jak na poniższym rysunku (fragment panelu Topology).

2. Przedstawić zrzut okna polecenia ilustrującego osiągalność utworzonej instancji spoza DC (z komputera studenckiego dołączonego do sieci laboratoryjnej ZSUT).

## 5. Część 2: OpenStack Heat
### 5.7 Utworzenie stosu
Stworzony został stos wykorzystując szablon z pliku `slcd-lab3-stack-heat-initialTopo.yml`. Poniżej przedstawiona jest uzyskana topologia. Aby dołączyć się z wykorzystaniem `ssh` do utworzonej maszyny `server-2` należało wyłączyć `Port security`.


### 5.8 Deklaratywna modyfikacja stosu
W istniejącym stosie wprowadziliśmy zmiany poprzez zmianę pliku opisującego stos na plik `slcd-lab3-stack-heat-targetTopo.yml`. Po przetworzeniu zmian widać, że infrastruktura została przekonfigurowana i jej stan jest zgodny z definicją zawartą w pliku.

# POLECENIA DO SPRAWOZDANIA
1. Po uruchomieniu przykładów zmodyfikować wg własnego wzorca nazwę maszyny wirtualnej oraz nazwy podsieci (2 i 3) tworzonych z szablonu, usunąć stos i wykreować go ponownie.
Dokonaliśmy edycji pliku `slcd-lab3-stack-heat-targetTopo.yml`, które dotyczyły głównie zmiany nazw poszczególnych komponentów. Zmiany jakie zaszły to:
* zamiana nazwy obrazu na `cirros-bejbiszarki-image`
* zmiana nazwy subnet-ów na odpowiednio `network-subnet_bejbiszarki_2` i `network-subnet_bejbiszarki_3`
* zmiana nazwy routera na `router_bejbiszarki_2`
* zmiana nazwy maszyny wirtualnej na `instance_bejbiszarki_2`
Zmiany w nazwach widać w kolejnym punkcie na zrzutach ekranu.
2. Przedstawić zrzut całego panelu Topology z topologią uzyskanej sieci i wyświetlonym opisem utworzonej maszyny wirtualnej (analogicznie, jak w p. 4.5, polecenie 1).
Na poniższych zrzutach ekranu widać zmiany nazwy maszyny wirtualnych, routera oraz samych podsieci.



3. Przedstawić zrzut okna polecenia ilustrującego osiągalność instancji spoza DC instancji utworzonej z szablonu.
Na poniższym zrzucie ekranu widać, że po wcześniejszym wyłączeniu `Port security` jesteśmy w stanie uzyskać powłokę systemu linux spoza DC.

4. Czy deklaratywna modyfikacja stosu działa „wstecz” – czy aplikując szablon initialTopodo DO stosu zgodnego z targetTopo można z powrotem przejść do topologii initialTopo?
Tak, możliwe jest powrócenie do wcześniejszego stanu. Mówimy tutaj o dwóch szablonach dostarczonych przez prowadzącego gdzie zgodne są nazwy w obu szablonach. Open stack usuwa komponenty, które nie znajdują się w obecnie wgrywanym szablonie.
Poniżej widać jeden z eventów w stworzonym przez nas stosie - widzimy event, w którym 2 resource-y są usuwane: `router2-patch-sub3` oraz `subnet3`.

# 5.9 Zadania dodatkowe/nieobowiązkowe
1. Zmodyfikować szablon initialTopo dodając odpowiednią grupę zabezpieczeń (security group) w ten sposób, aby instancja instance2 po wdrożeniu zmodyfikowanego stosu od razu była osiągalna spoza DC (osiągalna ssh lub ping).
Dodana zostałą security grupa. Zawiera ona dwie reguły. Pierwszy z nich odpowiedzialny jest za możliwość dostępu przez `ssh`. Dozwolona adresy to cała pula adresów IP. Drugi z nich to zezwolenie przychodzenie pakietów `icmp`. Obie reguły mają `direction` defaultowo ustawiony na `ingress`.
```yaml=
# security group
security-group:
type: OS::Neutron::SecurityGroup
properties:
name: { get_param: security-group-name }
rules:
- protocol: tcp
remote_ip_prefix: 0.0.0.0/0
port_range_min: 22
port_range_max: 22
- protocol: icmp
remote_ip_prefix: 0.0.0.0/0
# define instance to create
instance2:
type: OS::Nova::Server
properties:
name: server-2
image: { get_param: image-id }
flavor: { get_param: instance-flavor }
networks:
- network:
get_resource: network2
security_groups:
- get_param: default-security-group
- get_resource: security-group
user_data:
str_replace:
template: |
#!/bin/bash
echo "Hello, I am in subnetwork netName."
params:
netName: { get_attr: [subnet2, name] }
```
Po sprawdzeniu security group na hoście widzimy, że została dodana nowa grupa.

Możliwe jest pingowanie maszyny oraz możliwy jest dostęp do maszyny poprzez `ssh`.

2. Zmodyfikować szablon targetTopo w ten sposób, aby podczas wdrożenia szablonu instancja instance3 otrzymywała pływający adres IP; o odpowiednią grupę zabezpieczeń dla tej instancji zadbać szablonem lub ręcznie. Sprawdzić i potwierdzić zrzutem z ekranu osiągalność tej maszyny spoza DC oraz wzajemną osiągalność maszyn instance1, instance2 i instance3 (można na nie wejść po ssh lub użyć graficznej konsoli dashboru Heat).
W oby instanjach została użyta secure group taka, jak w poprzendim punkcie. Dodane zostały dwa dodatkowe recources, a mianowicie `FloatingIP` oraz `FloatingIPAssociation`. Pozwoliło to na uzyskanie floating ip w maszynie o nazwie `instance_bejbiszarki_3`.
<!-- hosty 2 i 3 w tej samej sieci prywatnej -->
```yaml=
instance3:
type: OS::Nova::Server
properties:
name: instance_6osub_3
image: { get_param: image-id }
flavor: { get_param: instance-flavor }
networks:
- network:
get_resource: network2
security_groups:
- get_param: default-security-group
- get_resource: security-group
# allocate floating IP to tenant project
floatingIP-3:
type: OS::Neutron::FloatingIP
properties:
floating_network_id: { get_param: external-network-name }
# attach allocated floating IP to the instance
association-floating-IP-3:
type: OS::Nova::FloatingIPAssociation
depends_on: [ instance3, floatingIP-3 ]
properties:
floating_ip: { get_resource: floatingIP-3 }
server_id: { get_resource: instance3 }
```
Poniżej znajujduje się podgląd na topologię sieci po wprowadzeniu wcześniej wspomnianych ulepszeń do konfiguracji stack-a.

Na poniższych dwóch zrzutach ekranu widzimy, że jesteśmy w stanie pingować wszystkie maszyny `instance_bejbiszarki_*`. Możliwe jest również połączenie się do każdej z nich poprzez `ssh` oraz z każdej maszyny do kolejnej.
**Ping:**

**ssh:**

3. W przypadku z punktu 2 sprawdzić, czy instancje mogą otrzymywać adres stały (wewnętrzny) z dowolnej z podsieci Network2-subnet2/Network2-subnet3. Jeśli nie, rozważyć teoretycznie (nie trzeba implementować), czy możliwa byłaby taka konstrukcja szablonu, aby każda z instancji uzyskiwała adres stały (prywatny) z wybranej podsieci. Wnioski przedstawić hasłowo (sama idea) w formie pisemnej.
Nie, instancje mogą otrzymywać tylko i wyłaćznie adresy z podsieci `Network2-subnet3`.
Możliwe jest, aby instancje otrzymały stały adres prywatny z wybranej podsieci. Aby to uczynić potrzebne jest zdefiniowanie resource typu `OS::Neutron::Port`, który w swoich properties będzie przetrzymywać `network_id` (czyli resource network2) oraz `fixed_ips` (statyczny adres z podsieci numer 2, maska nie jest potrzebna)
Dodatkowo, w takim typie resource zdefiniowany może zostać security_groups. Poniżej przykład zmiany dla instancji numer 2.
```yaml=
# security group
security-group:
type: OS::Neutron::SecurityGroup
properties:
name: { get_param: security-group-name }
rules:
- protocol: tcp
remote_ip_prefix: 0.0.0.0/0
port_range_min: 22
port_range_max: 22
- protocol: icmp
remote_ip_prefix: 0.0.0.0/0
# define instance port
instance2_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: network2 }
fixed_ips:
- ip_address: "192.168.11.3"
security_groups:
- get_param: default-security-group
- get_resource: security-group
# define instance to create
instance2:
type: OS::Nova::Server
properties:
name: instance_6osub_2
image: { get_param: image-id }
flavor: { get_param: instance-flavor }
networks:
- port: { get_resource: instance2_port }
```
Co więcej, możliwe jest dynamiczne ustawianie adresów IPv4. Aby to uczynić w resource typu `OS::Neutron::Port` zamiast statycznego adresu w `fixed_ips` nalezu podać `subnet_id` (resource subnet3). Poniżej przykład zmiany dla instancji numer 3.
```yaml=
# define instance port
instance3_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: network2 }
fixed_ips:
- subnet_id: { get_resource: subnet3 }
security_groups:
- get_param: default-security-group
- get_resource: security-group
# define instance to create
instance3:
type: OS::Nova::Server
properties:
name: instance_6osub_3
image: { get_param: image-id }
flavor: { get_param: instance-flavor }
networks:
- port: { get_resource: instance3_port }
```
Widzimy, że template został poprawnie wprowadzony. Instancja `instance_bejbiszarki_2` otrzymuje stały adres z puli adresów `subnet2` jako `192.168.11.3`, a `instance_bejbiszarki_3` otrzymała dynamicznie adres z puli adresów `subnet3`.


## 6 Podsumowanie laboratorium
Dzięki temu laboratorium zapoznaliśmy się z platformą OpenStack, nauczyliśmy się tworzyć podstawowe zasoby, oraz tworzyć stack'i z wykorzystaniem template'ów. Przybliżyło nam to mechanizmy tworzenia własnego chmurowego centrum danych oraz sposób zarządzania platformą typu `Infrastructure-as-a-Service (IaaS)`.
<!-- https://github.com/personium/openstack-heat/blob/master/02_personium_security_group.yaml -->
## Zmodyfikowany template na potrzeby zadań dodatkowych
```yaml=
heat_template_version: 2018-08-31
description: Simple template to deploy a tenant network with single instance - SLCD lab3.
parameters:
external-network-name:
type: string
description: Network to allocate floating IP from
default: external
dns-nameserver:
type: string
description: DNS Server for external access
default: 8.8.8.8
default-security-group:
type: string
description: Security group to be used
default: default
security-group-name:
type: string
description: Name of security group
default: Security group created for slcd lab3
image-id:
type: string
label: Image ID
description: Image to be used for compute instance
default: cirros-bejbiszarki-image
instance-flavor:
type: string
label: Instance Type
description: Flavor to be used for the instance
constraints:
- allowed_values: [ m1.tiny, m1.small, m1.medium, m1.large, m1.xlarge ]
description: Value must be one of m1.tiny, m1.large, m1.medium, m1.small, m1.xlarge.
default: m1.tiny
resources:
# tenant network
network2:
type: OS::Neutron::Net
properties:
admin_state_up: true
name: network_bejbiszarki
shared: false
# tenant subnetwork (address pool)
subnet2:
type: OS::Neutron::Subnet
properties:
cidr: 192.168.11.0/28
allocation_pools: [ {"start": "192.168.11.2", "end": "192.168.11.14" } ]
dns_nameservers: [ {get_param: dns-nameserver} ]
enable_dhcp: true
ip_version: 4
name:
str_replace:
template: __net__-subnet_bejbiszarki_2
params:
__net__: { get_attr: [network2, name] }
network_id:
get_resource: network2
# EXPERIMENTAL tenant subnetwork 3 (address pool)
subnet3:
type: OS::Neutron::Subnet
properties:
cidr: 192.168.11.16/28
allocation_pools: [ {"start": "192.168.11.18", "end": "192.168.11.30" } ]
dns_nameservers: [ {get_param: dns-nameserver} ]
enable_dhcp: true
ip_version: 4
name:
str_replace:
template: __net__-subnet_bejbiszarki_3
params:
__net__: { get_attr: [network2, name] }
network_id:
get_resource: network2
# tenant router attached to external network for external access of tenant instances
router2:
type: OS::Neutron::Router
properties:
admin_state_up: true
name: router_bejbiszarki_2
external_gateway_info: {
network: {get_param: external-network-name},
enable_snat: true
# this property is enabled for aministrative users only
}
# connect tenant subnetwork 2 to tenant router for external access
interface-router2-sub2:
type: OS::Neutron::RouterInterface
depends_on: [ router2, subnet2 ]
properties:
router: { get_resource: router2 }
subnet: { get_resource: subnet2 }
# EXPERIMENTAL connect tenant subnetwork 3 to tenant router for external access
interface-router2-sub3:
type: OS::Neutron::RouterInterface
depends_on: [ router2, subnet3 ]
properties:
router: { get_resource: router2 }
subnet: { get_resource: subnet3 }
# security group
security-group:
type: OS::Neutron::SecurityGroup
properties:
name: { get_param: security-group-name }
rules:
- protocol: tcp
remote_ip_prefix: 0.0.0.0/0
port_range_min: 22
port_range_max: 22
- protocol: icmp
remote_ip_prefix: 0.0.0.0/0
# define instance port
instance2_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: network2 }
fixed_ips:
- ip_address: "192.168.11.3"
security_groups:
- get_param: default-security-group
- get_resource: security-group
# define instance to create
instance2:
type: OS::Nova::Server
properties:
name: instance_bejbiszarki_2
image: { get_param: image-id }
flavor: { get_param: instance-flavor }
networks:
- port: { get_resource: instance2_port }
# allocate floating IP to tenant project
floatingIP-2:
type: OS::Neutron::FloatingIP
properties:
floating_network_id: { get_param: external-network-name }
# attach allocated floating IP to the instance
association-floating-IP-2:
type: OS::Nova::FloatingIPAssociation
depends_on: [ instance2, floatingIP-2 ]
properties:
floating_ip: { get_resource: floatingIP-2 }
server_id: { get_resource: instance2 }
# using device_id attribute of port instead of server id would work better with stack updates
# define instance port
instance3_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: network2 }
fixed_ips:
- subnet_id: { get_resource: subnet3 }
security_groups:
- get_param: default-security-group
- get_resource: security-group
# define instance to create
instance3:
type: OS::Nova::Server
properties:
name: instance_bejbiszarki_3
image: { get_param: image-id }
flavor: { get_param: instance-flavor }
networks:
- port: { get_resource: instance3_port }
# allocate floating IP to tenant project
floatingIP-3:
type: OS::Neutron::FloatingIP
properties:
floating_network_id: { get_param: external-network-name }
# attach allocated floating IP to the instance
association-floating-IP-3:
type: OS::Nova::FloatingIPAssociation
depends_on: [ instance3, floatingIP-3 ]
properties:
floating_ip: { get_resource: floatingIP-3 }
server_id: { get_resource: instance3 }
```