Cloudmonkey is distributed with Apache CloudStack, and allows for command line configuration of CloudStack resources – i.e. configuration of zones, networks, pods, clusters as well as adding hypervisors, primary and secondary storage.
Using an Ansible playbook to run CloudMonkey isn’t necessarily a good idea – writing a proper shell script with it’s own variable input will allow for much more dynamic configuration – Ansible doesn’t offer proper scripting capabilities after all.
Anyway, the following playbook will configure a CloudStack zone, adding pod, cluster, hypervisors and storage.
Pre-reqs as follows:
- Fully configured CloudStack management server(s) – see previous CloudStack playbook.
- Built and configured XenServer hosts.
- Two physical network stacks:
- VLAN segregation.
- Physical network 1: used for management and cloud tenant private traffic, as well as NFS storage. Network tagges as “cloud-private”.
- Physical network 2: used for public traffic, network tagged as “cloud-public”.
- XenServer networks configured with above tag names.
- NFS shares:
- Primary storage: NFS share as per CloudStack documentation.
- Secondary storage: NFS share as prepared during CloudStack installation (see CloudStack playbook post).
Usage as follows:
# ansible-playbook -i /etc/ansible/inventory/<ansible_inventory_file> --limit=<destination_host> /etc/ansible/cloudmonkey.yml
Cloudmonkey.yml
Full code is maintained on Github – https://github.com/dagsonstebo/CloudStack-Ansible-Playbook.
--- ######################################################################################### # Copyright 2015 Dag Sonstebo # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ######################################################################################### # # CLOUDMONKEY CONFIGURATION PLAYBOOK # # Used following CloudStack base install, playbook uses Cloudmonkey to configure # zone, networks, pods, clusters, XenServer hosts and primary/secondary storage. # # Prereqs and network topology: # - Fully built and running CloudStack management server. # - Built XenServer hosts, with cloud-private and cloud-public networks configured. # - Prepared NFS primary and secondary storage. # - VLAN segregation. # - Physical network 1: management and private traffic, tagged cloud-private. # - Physical network 2: public traffic, tagged cloud-public. # # Update variables and run with: # # ansible-playbook -i <inventory_file> --limit=<target_host> cloudmonkey.yml # # Playbook will prompt for: # - XenServer host password # # v1.0 280115 DS ######################################################################################### # - name: apply CloudStack configuration to all nodes hosts: all ######################################################################################### # Vars and vars_prompt # vars_prompt: - name: "XSPassword" prompt: "XenServer root password" private: yes vars: CMConfig: NFSHost: <NFS_hostname_or_IP_address_here> NFSSecondaryShare: <NFS_secondary_storage_share_here> NFSPrimaryShare: <NFS_primary_storage_share_here> PrimaryStoreName: <NFS_primary_storage_name_here> ZoneName: <Zone_name> PublicDNS1: <Public_DNS_IP_1> PublicDNS2: <Public_DNS_IP_2> InternalDNS1: <Private_DNS_IP_1> InternalDNS2: <Private_DNS_IP_2> GuestCIDR: 10.0.1.0/24 NetworkType: Advanced Phys1Name: <Physical_network_1_name> Phys1Isolation: VLAN Phys1VLANs: <Private_traffic_VLAN_range> Phys1TrafficType1: Management Phys1TrafficType1Label: cloud-private Phys1TrafficType2: Guest Phys1TrafficType2Label: cloud-private Phys2Name: <Physical_network_2_name> Phys2Isolation: VLAN Phys2VLANs: <Public_traffic_VLAN_or_blank> Phys2TrafficType1: Public Phys2TrafficType1Label: cloud-public PodName: <Pod_name> PodStartIP: <Pod_management_IP_range_start_IP> PodEndIP: <Pod_management_IP_range_end_IP> PodNetmask: <Pod_management_netmask> PodGateway: <Pod_management_default_gateway> PublicStartIP: <Public_IP_range_start_IP> PublicEndIP: <Public_IP_range_end_IP> PublicNetmask: <Public_netmask> PublicGateway: <Public_default_gateway> ClusterName: <Cluster_name> ClusterHypervisor: XenServer XSHostIP: <First_XenServer_host_IP> XSUsername: root ######################################################################################### # Tasks # tasks: - name: Validate input - XenServer host password fail: msg="Missing or incorrect XenServer password." when: XSPassword is not defined or ( XSPassword is defined and XSPassword == "" ) tags: - cmconfig ####################################################### # Configure first zone # - name: Configure zone and add resources shell: cloudmonkey create zone name={{ CMConfig.ZoneName }} dns1={{ CMConfig.PublicDNS1 }} dns2={{ CMConfig.PublicDNS2 }} internaldns1={{ CMConfig.InternalDNS1 }} internaldns2={{ CMConfig.InternalDNS2 }} guestcidraddress={{ CMConfig.GuestCIDR }} networktype={{ CMConfig.NetworkType }} localstorageenabled=false | grep ^id | awk '{print $3}' register: ZoneID tags: - cmconfig ####################################################### # Create first physical network and traffic types # - name: Create physical network 1 shell: cloudmonkey create physicalnetwork name={{ CMConfig.Phys1Name }} zoneid={{ ZoneID.stdout }} isolationmethods={{ CMConfig.Phys1Isolation }} vlan={{ CMConfig.Phys1VLANs }} | grep ^id | awk '{print $3}' register: Phys1ID tags: - cmconfig - name: Create traffic type on physical network 1 ({{ CMConfig.Phys1TrafficType1 }}) shell: cloudmonkey add traffictype physicalnetworkid={{ Phys1ID.stdout }} traffictype={{ CMConfig.Phys1TrafficType1 }} xennetworklabel={{ CMConfig.Phys1TrafficType1Label }} tags: - cmconfig - name: Create traffic type on physical network 1 ({{ CMConfig.Phys1TrafficType2 }}) shell: cloudmonkey add traffictype physicalnetworkid={{ Phys1ID.stdout }} traffictype={{ CMConfig.Phys1TrafficType2 }} xennetworklabel={{ CMConfig.Phys1TrafficType2Label }} tags: - cmconfig ####################################################### # Configure VR, VPC VR, LB VM # - name: Get network service provider ID for VR shell: cloudmonkey list networkserviceproviders name=VirtualRouter physicalnetworkid={{ Phys1ID.stdout }} | grep ^id | awk '{print $3}' register: Phys1VRID tags: - cmconfig - name: Get VR element shell: cloudmonkey list virtualrouterelements nspid={{ Phys1VRID.stdout }} | grep ^id | awk '{print $3}' register: Phys1VRElement tags: - cmconfig - name: Enable VR shell: cloudmonkey api configureVirtualRouterElement enabled=true id={{ Phys1VRElement.stdout }} tags: - cmconfig - name: Enable network service provider shell: cloudmonkey update networkserviceprovider state=Enabled id={{ Phys1VRID.stdout }} tags: - cmconfig - name: Get network service provider ID VPCR shell: cloudmonkey list networkserviceproviders name=VpcVirtualRouter physicalnetworkid={{ Phys1ID.stdout }} | grep ^id | awk '{print $3}' register: Phys1VPCVRID tags: - cmconfig - name: Get virtual VPC router element shell: cloudmonkey list virtualrouterelements nspid={{ Phys1VPCVRID.stdout }} | grep ^id | awk '{print $3}' register: Phys1VPCVRElement tags: - cmconfig - name: Enable VPC VR shell: cloudmonkey api configureVirtualRouterElement enabled=true id={{ Phys1VPCVRElement.stdout }} tags: - cmconfig - name: Enable network service provider shell: cloudmonkey update networkserviceprovider state=Enabled id={{ Phys1VPCVRID.stdout }} tags: - cmconfig - name: Get network service provider ID LBVM shell: cloudmonkey list networkserviceproviders name=InternalLbVm physicalnetworkid={{ Phys1ID.stdout }} | grep ^id | awk '{print $3}' register: Phys1LBVMID tags: - cmconfig - name: Get LBVM element shell: cloudmonkey list internalloadbalancerelements nspid={{ Phys1LBVMID.stdout }} | grep ^id | awk '{print $3}' register: Phys1LBVMVRElement tags: - cmconfig - name: Enable LBVM shell: cloudmonkey configure internalloadbalancerelement id={{ Phys1LBVMVRElement.stdout }} enabled=true tags: - cmconfig - name: Enable network service provider LBVM shell: cloudmonkey update networkserviceprovider state=Enabled id={{ Phys1LBVMID.stdout }} tags: - cmconfig - name: Enable physical network 1 shell: cloudmonkey update physicalnetwork state=Enabled id={{ Phys1ID.stdout }} tags: - cmconfig ####################################################### # Create physical network 2 and traffic type # - name: Create physical network 2 shell: cloudmonkey create physicalnetwork name={{ CMConfig.Phys2Name }} zoneid={{ ZoneID.stdout }} isolationmethods={{ CMConfig.Phys2Isolation }} vlan={{ CMConfig.Phys2VLANs }} | grep ^id | awk '{print $3}' register: Phys2ID tags: - cmconfig - name: Create traffic type on physical network 2 ({{ CMConfig.Phys2TrafficType1 }}) shell: cloudmonkey add traffictype physicalnetworkid={{ Phys2ID.stdout }} traffictype={{ CMConfig.Phys2TrafficType1 }} xennetworklabel={{ CMConfig.Phys2TrafficType1Label }} tags: - cmconfig - name: Add public network shell: cloudmonkey create vlaniprange zoneid={{ ZoneID.stdout }} startip={{ CMConfig.PublicStartIP }} endip={{ CMConfig.PublicEndIP }} netmask={{ CMConfig.PublicNetmask }} forvirtualnetwork=true gateway={{ CMConfig.PublicGateway }} physicalnetworkid={{ Phys2ID.stdout }} tags: - cmconfig - name: Enable physical network 2 shell: cloudmonkey update physicalnetwork state=Enabled id={{ Phys2ID.stdout }} tags: - cmconfig ######################################################## # Create pod and cluster # - name: Create pod in zone 1 shell: cloudmonkey create pod name={{ CMConfig.PodName }} startip={{ CMConfig.PodStartIP }} endip={{ CMConfig.PodEndIP }} netmask={{ CMConfig.PodNetmask }} gateway={{ CMConfig.PodGateway }} zoneid={{ ZoneID.stdout }} | grep ^id | awk '{print $3}' register: PodID tags: - cmconfig - name: Add cluster in zone 1 / pod 1 shell: cloudmonkey add cluster podid={{ PodID.stdout }} hypervisor={{ CMConfig.ClusterHypervisor }} clustertype=CloudManaged zoneid={{ ZoneID.stdout }} clustername={{ CMConfig.ClusterName }} | grep ^id | awk '{print $3}' register: ClusterID tags: - cmconfig - name: Add XS host shell: cloudmonkey add host zoneid={{ ZoneID.stdout }} podid={{ PodID.stdout }} clusterid={{ ClusterID.stdout }} hypervisor={{ CMConfig.ClusterHypervisor }} username={{ CMConfig.XSUsername }} password={{ XSPassword | mandatory }} url=http://{{ CMConfig.XSHostIP }} tags: - cmconfig ####################################################### # Add primary storage # - name: Add primary storage shell: cloudmonkey create storagepool zoneid={{ ZoneID.stdout }} podid={{ PodID.stdout }} clusterid={{ ClusterID.stdout }} name={{ CMConfig.PrimaryStoreName }} provider=nfs url=nfs://{{ CMConfig.NFSHost }}{{ CMConfig.NFSPrimaryShare }} tags: - cmconfig ####################################################### # Add secondary storage # - name: Add secondary storage shell: cloudmonkey add secondarystorage zoneid={{ ZoneID.stdout }} url=nfs://{{ CMConfig.NFSHost }}{{ CMConfig.NFSSecondaryShare }} tags: - cmconfig ####################################################### # Enable zone - name: Enable zone shell: cloudmonkey update zone allocationstate=Enabled id={{ ZoneID.stdout }} tags: - cmconfig