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

Um einen Eindruck von den Möglichkeiten zum Scripting mit Heat zu bekommen, habe ich etwas experimentiert und in den folgenden Beiträgen möchte ich das etwas dokumentieren. Da es meine ersten Versuche in diese Richtung sind, muss es nicht zwangsläufig alles ganz richtig oder vollständig sein, aber vielleicht ermöglicht es auch anderen einen ersten unkomplizierteren Einstieg in OpenStack und Heat.

Hier soll das folgende kleine Beispiel als flexibles Skript aufgebaut werden:

Es gibt einen Router, drei Server ein Netz. Die Server sollen in einem RFC1918-Netz liegen und so gibt es ein Subnet, das jedoch für bestimmte Dienste über NAT auch von außen zugänglich sein soll. Insgesamt werden in diesem Beispiel für die Switch vier Ports benötigt.

Die Heat-Komponente unterstützt die Formate JSON und YAML. Hier soll für die Beispiele YAML eingesetzt werden.

Die Beschreibung von YAML findet sich bei Wikipedia, einen Syntax-Checker für YAML findet sich z.B. unter http://yamllint.com/

Als Syntax kann CFN von Amazon eingesetzt werden oder hier im Beispiel HOT Heat Orchestration Template. Für die Übertragung von CFN-Skripten gibt es eine Umsetzungtabelle unter https://wiki.openstack.org/wiki/Heat/AWS-to-OpenStack-resource-mapping-in-templates

Skripte in Heat unterteilen sich in verschiedenen Bereiche

  • heat_template_version: 2013-05-23 (zur Deklaration eines HOT-Templates)
  • description (für die Beschreibung des Templates an sich)
  • parameter-groups (für Gruppen von Parametern) (funktioniert noch nicht, anscheinend erst ab dem JUNO-release von OpenStack)
  • parameters (zur Abfrage von Angaben beim Nutzer)
  • resources (zur Deklaration der eigentlichen Ressourcen der Umgebung) (MANDATORY)
  • outputs (zur Vereinbarung von Ausgaben bei erfolgreicher Durchführung des Skripts)

Für den wichtigsten Resource-Bereich gibt es eine vollständige Dokumentation unter http://docs.openstack.org/developer/heat/template_guide/openstack.html

In YAML werden Hierarchien durch Einrückungen ausgedrückt, wie viele Leerzeichen eingefügt werden spielt dabei keine Rolle, solange es einheitlich ist. Bei mir im Editor hat es mit „Tabs“ nicht so gut funktioniert. Ein einfaches Beispiel könnte so aussehen:

parameters:
 dns_server1:
  type: string
  default: 141.20.1.3
  description: DNS 1 for this stack

Hier ergibt sich durch die Einrückungen die Hierarchie -> Parameters -> dns_server1 -> type:, default:, description:.

„Parameters“ markiert den Bereich des Skripts, dns_server1: definiert ein Objekt mit den Parametern type:, default: und description: .

Der Teil „parameter-groups“ dient der Sortierung von Parametern, die sonst in beliebiger Reihenfolge angezeigt werden. Im ICEHOUSE-Release scheint dieses Feature noch nicht vollständig unterstütz zu sein. Für den JUNO-Release soll sich die Unterstützung jedoch verbessern. Die Sortierungen haben die Form:

parameter_groups:
- label: <human-readable label of parameter group>
  description: <description of the parameter group>
  parameters:
  - <param name>
  - <param name>

Für dieses Skript könnte eine Sortierung wie folgt aussehen:

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 the OpenStack installation
  parameters:
  - keypair_name
  - image_id
  - external_net_id
  - machine_flavor

Die Parameter an sich werden im nächsten Bereich „parameters“ erst definiert und können dann in den „parameter-groups“ per Namen referenziert werden.

Als Parameter sollen in dem Skript die wichtigsten Angaben vom Anwender abgefragt werden, der restliche Aufbau soll automatisch geschehen.

Die Möglichkeiten für „parameters“ sind:

parameters:
  <param name>:
    type: <string | number | json | comma_delimited_list | boolean>
    label: <human-readable name of the parameter>
    description: <description of the parameter>
    default: <default value for parameter>
    hidden: <true | false>
    constraints:
      <parameter constraints>

Die folgenden Parameter werden abgefragt:

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.tiny, m1.small, m1.large]
     description: Value must be one of 'm1.tiny', 'm1.small' or 'm1.large'

Fügt man dieses Skript über das Web-Interface über Project -> Orchestration -> Stacks -> Launch Stacks -> Template Source: Direct Input

ein, validiert es noch nicht, da nur „parameters“ als Bereich eingesetzt wurde und ein „resources“-Bereich fehlt, der verpflichtend ist..

(Der Bereich „Environment Source“ beim Anlegen eines Templates im Web-Interface kann für weitere Voreinstellungen genutzt werden, die in mehreren Skripten eingesetzt werden sollen.)

 

Die ersten Ressourcen werden ein „network“ und ein „subnet“ sein. Die Möglichkeiten hier für das „network“ sind:

 type: OS::Neutron::Net
 properties:
  admin_state_up: Boolean
  dhcp_agent_ids: [Value, Value, ...]
  name: String
  shared: Boolean
  value_specs: {...} 

und für das „subnet“

 type: OS::Neutron::Subnet
 properties:
  allocation_pools: [{"start": String, "end": String}, {"start": String, "end": String}, ...]
  cidr: String
  dns_nameservers: [Value, Value, ...]
  enable_dhcp: Boolean
  gateway_ip: String
  host_routes: [{"nexthop": String, "destination": String}, {"nexthop": String, "destination": String}, ...]
  ip_version: Integer
  name: String
  network_id: String
  tenant_id: String
  value_specs: {...}

Wenn es nur die nötigsten Einträge sein sollen wird dies zu:

heat_template_version: 2013-05-23
description: My First Heat Template
resources:
 my_first_network:
  type: OS::Neutron::Net
  properties:
  name: My1Net
my_first_subnet:
 type: OS::Neutron::Subnet
 properties:
  allocation_pools: [ { start: 192.168.0.100, end: 192.168.0.200 } ]
  cidr: 192.168.0.0/24
  dns_nameservers: [ 141.20.1.3, 141.20.1.31 ]
  enable_dhcp: true
  gateway_ip: 192.168.0.1
  network_id: { get_resource: my_first_network }
  name: My1Subnet

Die meisten Angaben sind hier selbsterklärend. In der Zeile network_id: { get_resource: my_first_network } wird über den Befehl „get_resource:“ anstelle einer sonst anzugebenden eindeutigen ID (Objekt-UUID) als Zahl, die ID des Objekts „my_first_network“ dynamisch ersetzt. (Solche IDs sehen bei OpenStack als Zahl überlichweise aus wie z. B. „5f32fcf1-fbaf-47bf-9d39-9effbe750b97″)

Um die in der „parameters“-Sektion abgefragten Werte einzusetzen, wird über „get_param“ der Wert abgefragt und so könnte die Vereinbarung der DHCP-IP-Bereiche so aussehen:

allocation_pools: [ { start: { get_param: ip_start }, end: { get_param: ip_end } } ]

Das Skript oben läuft schon erfolgreich durch, wenn im folgenden Dialog noch der Name für den Stack vergeben wird und das Schlüsselpaar und eigene Passwort eingetragen wird. Die Option „Rollback On Failure:“ ist hilfreich, um im Fehlerfalle nicht alle bis zum Fehler angelegten Komponenten mühsam einzeln wieder löschen zu müssen, erschwert aber auch das Debuggen, da ein fehlerhafter Stack sofort wieder rückabgewickelt (gelöscht) wird.

Step 2

Der erzeugte Stack sieht dann z.B. folgendermaßen aus:

 

14. August 2014 | Veröffentlicht von Malte Dreyer
Veröffentlicht unter Technik
Verschlagwortet mit , ,

Schreiben Sie einen Kommentar

(erforderlich)