Die HU Cloud… Ein Beispiel mit Script (Teil 3)

Im dritten Teil zur Erstellung des Skripts werden noch die Server angelegt, ein Server wird auf eine öffentliche IP per NAT gelegt, einige Parameter abgefragt und die wichtigsten Daten mit ausgegeben.

Die Vorlage für Server ist umfangreicher:

  type: OS::Nova::Server
  properties:
   admin_pass: String
   availability_zone: String
   block_device_mapping: [{"volume_size": Integer, "volume_id": String, "snapshot_id": String, "delete_on_termination": Boolean, "device_name": String}, {"volume_size": Integer, "volume_id": String, "snapshot_id": String, "delete_on_termination": Boolean, "device_name": String}, ...]
   config_drive: Boolean
   diskConfig: String
   flavor: String
   flavor_update_policy: String
   image: String
   image_update_policy: String
   key_name: String
   metadata: {...}
   name: String
   networks: [{"port": String, "fixed_ip": String, "uuid": String, "network": String}, {"port": String, "fixed_ip": String, "uuid": String, "network": String}, ...]
   personality: {...}
   reservation_id: String
   scheduler_hints: {...}
   security_groups: [Value, Value, ...]
   software_config_transport: String
   user_data: String
   user_data_format: String

Eine Kurzbeschreibung der Parameter findet sich in der OpenStack-Dokumentation.

Für dieses Beispiel sind nur einige wenige Angaben notwendig. Über „key_name“ wird der Name des Schlüsselpaares aus den Eingangs-Parametern abgefragt. Die Art (Größe) des Servers, wird über den Parameter „flavor“ ausgewählt. „image“ ist hier über eine ID zu einem Ubuntu14-Image selektiert. Die „networks“ werden an „port“ und „network“ gebunden, die im zweiten Teil des Skripts definiert wurden: Server1 an Port1, Server2 an Port2, Server3 an Port3.

Um nach dem Booten des Servers noch Konfigurationen durchzuführen, wird bei Server1 über „user_data“ ein Skript ausgeführt.

So ergeben sich die drei Skripte für die Server zu:

 my_server1:
  type: OS::Nova::Server
  properties:
   name: WebServer1
   key_name: { get_param: keypair_name }
   flavor: { get_param: machine_flavor }
   image: { get_param: image_id }
   networks: [{ "port": { get_resource: my_port1 }, "network": { get_resource: my_first_network }}]
   user_data: |
    #!/bin/bash
    /bin/touch /tmp/nova-was-here

 my_server2:
  type: OS::Nova::Server
  properties:
   name: DBServer1
   key_name: { get_param: keypair_name }
   flavor: { get_param: machine_flavor }
   image: { get_param: image_id }
   networks: [{ "port": { get_resource: my_port2 }, "network": { get_resource: my_first_network }}]

 my_server3:
  type: OS::Nova::Server
  properties:
   name: DBServer2
   key_name: { get_param: keypair_name }
   flavor: { get_param: machine_flavor }
   image: { get_param: image_id }
   networks: [{ "port": { get_resource: my_port3 }, "network": { get_resource: my_first_network }}]

 

Für den Zugriff auf den Server1 von außen ist noch die Vergabe einer echten IP notwendig. Dies geschieht über

 my_floatingip:
  type: OS::Neutron::FloatingIP
  properties:
   floating_network_id: { get_param: external_net_id }
   port_id: { get_resource: my_port1 }

Wobei die ID für das externe Netzwerk in jeder Installation verschieden ist und von Nicht-Admins nicht dynamisch abgefragt werden kann.

Nützlich ist noch die Ausgabe der Attribute für die nun erzeugten Ressourcen. Hierfür kann die „outputs“-Sektion des Skripts benutzt werden:

outputs:
 ServerIP:
  value:
   str_replace:
    template: Öffentliche IP ist hostip
    params:
     hostip: { get_attr: [my_floatingip, floating_ip_address] } 
 FloatingIP:
  value: { get_attr: [my_floatingip, show ] }
 Network:
  value: { get_attr: [my_first_network, show] }
 Subnet:
  value: { get_attr: [my_first_subnet, show] }
 Server1:
   value: { get_attr: [ my_server1, show ] }
 Server2:
   value: { get_attr: [ my_server2, show ] }
 Server3:
   value: { get_attr: [ my_server3, show ] }
 Port1:
   value: { get_attr: [ my_port1, show ] }
 Port4:
   value: { get_attr: [ my_port4, show ] }

ServerIP fragt exemplarisch die vergebene öffentliche IP ab und gibt diese aus. „hostip“ ist hier eine Variable. Mittels der Funktion „str_replace“ wird der Parameter „hostip“ im Template dynamisch durch die vergebene IP-Adresse ersetzt.

Über „get_attr“ lassen sich für die erzeugten Ressourcen Attribute abfragen. Über das Attribut „show“ werden alle Attribute ausgegeben, es lassen sich jedoch auch einzelne Angaben gezielt auswählen. Eine Liste der möglichen Attribute findet sich bei jedem Objekt in der Doku jeweils unter dem Bereich „Attributes“.

Der vollständige Stack sieht dann in Horizon schon komplexer aus:

stack-t20

 

Das vollständige Skript ist nun schon recht lang geworden:

heat_template_version: 2013-05-23

description: My First Heat Template

parameter_groups:
- label: IP Settings
  description: Groups all the IPv4 settings
  parameters: 
  - cidr_net
  - ip_start
  - ip_end
  - gateway_address
  - dns_server1
  - dns_server2
- label: Open Stack Settings
  description: All settings about OpenStack
  parameters:
  - keypair_name
  - image_id
  - external_net_id
  - machine_flavor

parameters:
 cidr_net:
  type: string
  default: 192.168.0.0/24
  description: Size of the ip-net
 dns_server1:
  type: string
  default: 141.20.1.3
  description: DNS 1 for this stack
 dns_server2:
  type: string
  default: 141.20.1.31
  description: DNS 2 for this stack
 ip_start:
  type: string
  default: 192.168.0.100
  description: DHCP start address for this stack
 ip_end:
  type: string
  default: 192.168.0.200
  description: DHCP end address for this stack
 gateway_address:
  type: string
  default: 192.168.0.1
  description: IP address of the gateway
 keypair_name:
  type: string
  default: MyNewKeys
  description: Which keypair should be used
 image_id:
  type: string
  default: YOUR_IMAGE_ID_HERE
  description: Put your favorite image ID here
 external_net_id:
  type: string
  default: YOUR_EXT_NET_ID_HERE
  description: Ask your administrator for the external_network_id
 machine_flavor:
  type: string
  default: m1.small
  description: Your machine flavor to be used for this server.
  constraints:
   - allowed_values: [m1.nano, m1.tiny, m1.small, m1.large]
     description: Value must be one of 'm1.tiny', 'm1.small' or 'm1.large'

resources:
 my_first_network:
  type: OS::Neutron::Net
  properties:
   name: My1Net

 my_first_subnet:
  type: OS::Neutron::Subnet
  properties:
   allocation_pools: [ { start: { get_param: ip_start }, end: { get_param: ip_end } } ]
   cidr: { get_param: cidr_net }
   dns_nameservers: [ { get_param: dns_server1 }, { get_param: dns_server2 } ]
   enable_dhcp: true
   gateway_ip: { get_param: gateway_address }
   network_id: { get_resource: my_first_network }
   name: My1Subnet

 my_basic_security_group:
  type: OS::Neutron::SecurityGroup
  properties:
   description: Allow ICMP, SSH
   name: BasicRules
   rules: [
    {remote_ip_prefix: 0.0.0.0/0,
    direction: ingress,
    protocol: tcp,
    port_range_min: 22,
    port_range_max: 22},
    {remote_ip_prefix: 0.0.0.0/0,
    direction: ingress,
    protocol: icmp},
    {remote_ip_prefix: 0.0.0.0/0,
    direction: egress,
    protocol: icmp}]

 my_http_security_group:
  type: OS::Neutron::SecurityGroup
  properties:
   description: Allow HTTP
   name: HTTPRules
   rules: [
    {remote_ip_prefix: 0.0.0.0/0,
    direction: ingress,
    protocol: tcp,
    port_range_min: 80,
    port_range_max: 80}]

 my_router_security_group:
  type: OS::Neutron::SecurityGroup
  properties:
   description: Allow All
   name: RouterRules
   rules: [
    {remote_ip_prefix: 0.0.0.0/0,
    direction: ingress},
    {remote_ip_prefix: 0.0.0.0/0,
    direction: egress}]

 my_port1:
  type: OS::Neutron::Port
  properties:
   admin_state_up: true
   name: Port01
   network_id: { get_resource: my_first_network }
   security_groups: [ {get_resource: my_basic_security_group }, { get_resource: my_http_security_group } ]

 my_port2:
  type: OS::Neutron::Port
  properties:
   admin_state_up: true
   name: Port02
   network_id: { get_resource: my_first_network }
   security_groups: [ { get_resource: my_basic_security_group } ]

 my_port3:
  type: OS::Neutron::Port
  properties:
   admin_state_up: true
   name: Port03
   network_id: { get_resource: my_first_network }
   security_groups: [ { get_resource: my_basic_security_group } ]

 my_port4:
  type: OS::Neutron::Port
  properties:
   admin_state_up: true
   name: Port04
   network_id: { get_resource: my_first_network }
   fixed_ips: [{ "subnet_id": { get_resource: my_first_subnet }, "ip_address": { get_param: gateway_address } }]
   security_groups: [ { get_resource: my_router_security_group } ]

 my_router:
  type: OS::Neutron::Router
  properties:
   admin_state_up: true
   name: MyRouter

 my_router_gateway:
  type: OS::Neutron::RouterGateway
  properties:
   network_id: { get_param: external_net_id }
   router_id: { get_resource: my_router }

 my_router_int:
  type: OS::Neutron::RouterInterface
  properties:
   router_id: { get_resource: my_router }
   port_id: { get_resource: my_port4 }
 
 my_server1:
  type: OS::Nova::Server
  properties:
   name: WebServer1
   key_name: { get_param: keypair_name }
   flavor: { get_param: machine_flavor }
   image: { get_param: image_id }
   networks: [{ "port": { get_resource: my_port1 }, "network": { get_resource: my_first_network }}]
   user_data: |
    #!/bin/bash
    /bin/touch /tmp/nova-was-here

 my_server2:
  type: OS::Nova::Server
  properties:
   name: DBServer1
   key_name: { get_param: keypair_name }
   flavor: { get_param: machine_flavor }
   image: { get_param: image_id }
   networks: [{ "port": { get_resource: my_port2 }, "network": { get_resource: my_first_network }}]

 my_server3:
  type: OS::Nova::Server
  properties:
   name: DBServer2
   key_name: { get_param: keypair_name }
   flavor: { get_param: machine_flavor }
   image: { get_param: image_id }
   networks: [{ "port": { get_resource: my_port3 }, "network": { get_resource: my_first_network }}]

 my_floatingip:
  type: OS::Neutron::FloatingIP
  properties:
   floating_network_id: { get_param: external_net_id }
   port_id: { get_resource: my_port1 }

outputs:
 ServerIP:
  value:
   str_replace:
    template: Öffentliche IP ist hostip
    params:
     hostip: { get_attr: [my_floatingip, floating_ip_address] } 
 FloatingIP:
  value: { get_attr: [my_floatingip, show ] }
 Network:
  value: { get_attr: [my_first_network, show] }
 Subnet:
  value: { get_attr: [my_first_subnet, show] }
 Server1:
   value: { get_attr: [ my_server1, show ] }
 Server2:
   value: { get_attr: [ my_server2, show ] }
 Server3:
   value: { get_attr: [ my_server3, show ] }
 Port1:
   value: { get_attr: [ my_port1, show ] }
 Port4:
   value: { get_attr: [ my_port4, show ] }


9. September 2014 | Veröffentlicht von Malte Dreyer
Veröffentlicht unter Technik
Verschlagwortet mit , ,

Schreiben Sie einen Kommentar

(erforderlich)