Skip to content

Instantly share code, notes, and snippets.

@keyz182
Last active April 26, 2017 21:17
Show Gist options
  • Save keyz182/9322a4506d5baf89d57b to your computer and use it in GitHub Desktop.
Save keyz182/9322a4506d5baf89d57b to your computer and use it in GitHub Desktop.
Openstack Heat template for MongoDB Replica Set
heat_template_version: 2014-10-16
description: >
Deploy a MongoDB replica set on
OpenStack Powered Cloud (Openstack Juno)
Maintainer - Kieran Evans <[email protected]> | Github @keyz182
parameters:
replica_name:
type: string
description: Replica Name
default: rp0
secondary_count:
description: Number of secondaries
type: number
default: 2
constraints:
- range:
min: 2
description: Must be at least 2.
keyname:
type: string
description: Name of keypair to be used for compute instance
default: kieran
constraints:
- custom_constraint: nova.keypair
flavor:
type: string
default: d1.large
constraints:
- custom_constraint: nova.flavor
- allowed_values:
- m1.small
- m1.medium
- m1.large
- d1.large
- m1.xlarge
description: |
Must be a valid flavor
ubuntu_image:
type: string
description: Ubuntu 14.04
default: d41b5a8b-d1f0-48ed-bb54-952435d759a4
constraints:
- custom_constraint: glance.image
description: Must identify an image known to Glance
storage_volume_size:
type: number
description: Size of the volume to be created for storage node.
default: 512
constraints:
- range: { min: 128, max: 1024 }
description: must be between 128 and 1024 Gb.
timeout:
description: Wait condition timeout seconds
type: number
default: 600
floating-network-id:
type: string
label: Floating Network ID
description: UUID of the external network. The private network created by this stack will route to this network. Any floating IP addresses needed by this stack will also route to this network.
default: d6a726a2-14e9-42ab-bab2-07df1b418cd0
resources:
stack_security:
type: OS::Neutron::SecurityGroup
properties:
name:
list_join: [ '-', [ { get_param: 'OS::stack_name' }, "mongodb" ] ]
rules: [
{remote_ip_prefix: 0.0.0.0/0,
protocol: tcp,
port_range_min: 22,
port_range_max: 22},
{remote_ip_prefix: 10.10.20.0/24,
protocol: tcp,
port_range_min: 27017,
port_range_max: 27017},
{remote_ip_prefix: 0.0.0.0/0,
protocol: icmp}]
mongodb_network:
type: OS::Neutron::Net
properties:
admin_state_up: true
name:
list_join: [ '-', [ { get_param: 'OS::stack_name' }, "mongodb-net" ] ]
mongodb_subnet:
type: OS::Neutron::Subnet
properties:
name:
list_join: [ '-', [ { get_param: 'OS::stack_name' }, "mongodb_subnet"] ]
cidr: "10.10.20.0/24"
gateway_ip: "10.10.20.1"
allocation_pools: [{"start": "10.10.20.2", "end": "10.10.20.254"}]
dns_nameservers: [10.239.40.2, 10.239.40.130]
enable_dhcp: true
network_id: { get_resource: mongodb_network }
mongodb_router:
type: OS::Neutron::Router
properties:
name:
list_join: [ '-', [{ get_param: 'OS::stack_name' }, "mongodb_router"] ]
admin_state_up: true
mongodb_router_gw:
type: OS::Neutron::RouterGateway
properties:
network_id: { get_param: floating-network-id }
router_id: { get_resource: mongodb_router }
mongodb_router_interface:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: mongodb_router }
subnet_id: { get_resource: mongodb_subnet }
master_floatingip:
type: OS::Neutron::FloatingIP
properties:
floating_network_id:
get_param: floating-network-id
master_port:
type: OS::Neutron::Port
properties:
security_groups:
- get_resource: stack_security
network_id:
get_resource: mongodb_network
master_floatingip_association:
type: OS::Neutron::FloatingIPAssociation
properties:
floatingip_id:
get_resource: master_floatingip
port_id:
get_resource: master_port
master_pubkey_wait_handle:
type: OS::Heat::WaitConditionHandle
master_pubkey_wait_condition:
type: OS::Heat::WaitCondition
properties:
handle: { get_resource: master_pubkey_wait_handle }
timeout: { get_param: timeout }
master_privkey_wait_handle:
type: OS::Heat::WaitConditionHandle
master_privkey_wait_condition:
type: OS::Heat::WaitCondition
properties:
handle: { get_resource: master_privkey_wait_handle }
timeout: { get_param: timeout }
master_volume:
type: OS::Cinder::Volume
properties:
size: { get_param: storage_volume_size }
master_volume_attachment:
type: OS::Cinder::VolumeAttachment
properties:
volume_id: { get_resource: master_volume }
instance_uuid: { get_resource: master }
mountpoint: /dev/vdb
master:
type: OS::Nova::Server
properties:
key_name: { get_param: keyname }
image: { get_param: ubuntu_image }
flavor: { get_param: flavor }
name:
list_join: [ '-', [{ get_param: 'OS::stack_name' }, 'master'] ]
networks:
- port:
get_resource: master_port
user_data_format: RAW
user_data:
str_replace:
template: |
#cloud-config
# Update apt database on first boot
apt_update: true
# Upgrade the instance on first boot
apt_upgrade: true
# Add 10gen MongoDB repo
apt_sources:
- source: "deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen"
keyid: 7F0CEB10
filename: 10gen.list
# Install packages
packages:
- ntp
- mongodb-10gen
mounts:
[ vdb, /var/lib/mongodb ]
write_files:
- path: /run/addrepl.sh
permissions: 0755
content: |
#!/bin/bash
IP=$1
HOSTNAME=$2
#Add new hostname to hosts
echo "$IP $HOSTNAME" >> /etc/hosts
IPS=$(awk 'NF' /etc/hosts | grep -v "#" | grep -v 'local' | grep -v 'ip6' | awk '{print $1}')
#Propagate new hosts file to known hosts
for ip in $IPS
do
#Root ssh disabled by default, rather than enable, copy, then sudo mv
scp -o "UserKnownHostsFile /dev/null" -o "StrictHostKeyChecking no" /etc/hosts ubuntu@$ip:/home/ubuntu/hosts
ssh -o "UserKnownHostsFile /dev/null" -o "StrictHostKeyChecking no" ubuntu@$ip "sudo mv /home/ubuntu/hosts /etc/hosts"
done
#Add this new host to the replica set
CURRENTHOSTNAME=$(hostname)
mongo --norc --host $CURRENTHOSTNAME:27017 --eval "printjson(rs.add('$HOSTNAME:27017'))"
- path: /run/wcnotify.sh
permissions: '0755'
content: |
#!/bin/bash
service mongodb stop
sleep 5
#Add own hostname + ip to /etc/hosts
MYIP="`ifconfig | grep eth0 -A1 | sed -n '2 p' | awk '{print $2}' | awk -F":" '{print $2}'`"
HOSTNAME=$(hostname)
echo "$MYIP $HOSTNAME" >> /etc/hosts
sed -i "s/# replSet = setname/replSet = %rpname%/g" /etc/mongodb.conf
echo "rest=true" >> /etc/mongodb.conf
#Sleep to give mongo a chance to wake up
service mongodb start
#init the mongo replica set
until mongo --eval 'printjson(rs.initiate())'
do
echo "MongoDB not ready, trying again in 5 seconds"
sleep 5
done
mongo --eval "printjson(rs.conf())"
mongo --eval "printjson(rs.status())"
cat /var/log/mongodb/mongodb.log
#create new ssh keys for inter-comms
mkdir -p /root/.ssh/
ssh-keygen -f /root/.ssh/id_rsa -t rsa -N ''
mkdir -p /home/ubuntu/.ssh/
cp /root/.ssh/id_rsa /home/ubuntu/.ssh/
cp /root/.ssh/id_rsa.pub /home/ubuntu/.ssh/
cat /home/ubuntu/.ssh/id_rsa.pub >> /home/ubuntu/.ssh/authorized_keys
chown ubuntu:ubuntu -R /home/ubuntu/.ssh/
chmod 755 /home/ubuntu/.ssh
chmod 600 /home/ubuntu/.ssh/*
chmod 644 /home/ubuntu/.ssh/authorized_keys
#Send new ssh keys to other hosts via Waitconditions
PRIVKEY=$(base64 -w0 /home/ubuntu/.ssh/id_rsa)
PUBKEY=$(base64 -w0 /home/ubuntu/.ssh/id_rsa.pub)
%wc_notify_pub% --data-binary "{\"status\" : \"SUCCESS\",\"reason\" : \"Configuration OK\",\"data\" : \"$PUBKEY\"}"
%wc_notify_priv% --data-binary "{\"status\" : \"SUCCESS\",\"reason\" : \"Configuration OK\",\"data\" : \"$PRIVKEY\"}"
runcmd:
- [ bash, -x, /run/wcnotify.sh ]
params:
"%rpname%" : { get_param: replica_name }
"%wc_notify_pub%": { get_attr: [master_pubkey_wait_handle, curl_cli] }
"%wc_notify_priv%": { get_attr: [master_privkey_wait_handle, curl_cli] }
secondary_wait_handle:
type: OS::Heat::WaitConditionHandle
secondary_wait_condition:
type: OS::Heat::WaitCondition
properties:
handle: { get_resource: secondary_wait_handle }
timeout: { get_param: timeout }
count: { get_param: secondary_count }
secondary:
type: "OS::Heat::ResourceGroup"
depends_on: master_pubkey_wait_condition
depends_on: master_privkey_wait_condition
properties:
count: { get_param: secondary_count }
resource_def: {type: mongo-repl_secondary.yaml}
outputs:
master_public_ip:
description: The Public IP Address of the Master
value: { get_attr: [master_floatingip, floating_ip_address] }
master_ip:
value: { get_attr: [ master, first_address ] }
description: The IP of the Master
secondary_ips:
value: { get_attr: [ secondary, first_address ] }
description: The IP of the secondary
heat_template_version: 2014-10-16
parameters:
replica_name:
type: string
description: Replica Name
default: rp0
secondary_count:
description: Number of secondaries
type: number
default: 2
constraints:
- range:
min: 2
description: Must be at least 2.
keyname:
type: string
description: Name of keypair to be used for compute instance
default: kieran
constraints:
- custom_constraint: nova.keypair
flavor:
type: string
default: d1.large
constraints:
- custom_constraint: nova.flavor
- allowed_values:
- m1.small
- m1.medium
- m1.large
- d1.large
- m1.xlarge
description: |
Must be a valid flavor
ubuntu_image:
type: string
description: Ubuntu 14.04
default: d41b5a8b-d1f0-48ed-bb54-952435d759a4
constraints:
- custom_constraint: glance.image
description: Must identify an image known to Glance
storage_volume_size:
type: number
description: Size of the volume to be created for storage node.
default: 512
constraints:
- range: { min: 128, max: 1024 }
description: must be between 128 and 1024 Gb.
timeout:
description: Wait condition timeout seconds
type: number
default: 600
floating-network-id:
type: string
label: Floating Network ID
description: UUID of the external network. The private network created by this stack will route to this network. Any floating IP addresses needed by this stack will also route to this network.
default: d6a726a2-14e9-42ab-bab2-07df1b418cd0
resources:
secondary_wait_handle:
type: OS::Heat::WaitConditionHandle
secondary_wait_condition:
type: OS::Heat::WaitCondition
properties:
handle: { get_resource: secondary_wait_handle }
timeout: { get_param: timeout }
count: { get_param: secondary_count }
volume:
type: OS::Cinder::Volume
properties:
size: { get_param: storage_volume_size }
volume_attachment:
type: OS::Cinder::VolumeAttachment
properties:
volume_id: { get_resource: volume }
instance_uuid: { get_resource: instance }
mountpoint: /dev/vdb
instance:
type: OS::Nova::Server
properties:
key_name: { get_param: keyname }
image: { get_param: ubuntu_image }
flavor: { get_param: flavor }
name:
list_join: [ '-', [{ get_param: 'OS::stack_name' },'secondary_%index%'] ]
networks:
- network: { get_resource: mongodb_network }
security_groups:
- get_resource: stack_security
user_data_format: RAW
user_data:
str_replace:
template: |
#cloud-config
# Update apt database on first boot
apt_update: true
# Upgrade the instance on first boot
apt_upgrade: true
# Add 10gen MongoDB repo
apt_sources:
- source: "deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen"
keyid: 7F0CEB10
filename: 10gen.list
# Install packages
packages:
- mongodb-10gen
- ntp
mounts:
[ vdb, /var/lib/mongodb ]
write_files:
- path: /run/wcnotify.sh
permissions: '0755'
content: |
#!/bin/bash
#SSH from waitcond is returned as json {"1":"blah"}, do some magic to extract
mkdir -p /root/.ssh/
mkdir -p /home/ubuntu/.ssh/
echo '%privkey%' | python -mjson.tool | grep "1" | awk '{print $2}' | sed 's/"//g' | base64 --decode > /root/.ssh/id_rsa
echo '%pubkey%' | python -mjson.tool | grep "1" | awk '{print $2}' | sed 's/"//g' | base64 --decode > /root/.ssh/id_rsa.pub
cp /root/.ssh/id_rsa /home/ubuntu/.ssh/
cp /root/.ssh/id_rsa.pub /home/ubuntu/.ssh/
cat /home/ubuntu/.ssh/id_rsa.pub >> /home/ubuntu/.ssh/authorized_keys
#copy ssh keys into place
chown ubuntu:ubuntu -R /home/ubuntu/.ssh/
chmod 755 /home/ubuntu/.ssh
chmod 755 /root/.ssh
chmod 600 /root/.ssh/*
chmod 600 /home/ubuntu/.ssh/*
chmod 644 /home/ubuntu/.ssh/authorized_keys
MYIP="`ifconfig | grep eth0 -A1 | sed -n '2 p' | awk '{print $2}' | awk -F":" '{print $2}'`"
HOSTNAME=$(hostname)
sed -i "s/# replSet = setname/replSet = %rpname%/g" /etc/mongodb.conf
echo "rest=true" >> /etc/mongodb.conf
service mongodb restart
#Sleep to give mongo a chance to wake up
until mongo --eval 'printjson({})'
do
echo "MongoDB not ready, trying again in 5 seconds"
sleep 5
done
#Remotely run addrepl on the master to add myself to the replica set
ssh -o "UserKnownHostsFile /dev/null" -o "StrictHostKeyChecking no" ubuntu@%master% "sudo bash -x /run/addrepl.sh $MYIP $HOSTNAME"
%wc_notify% --data-binary "{\"status\" : \"SUCCESS\",\"reason\" : \"Configuration OK\"}"
runcmd:
- [ bash, -x, /run/wcnotify.sh ]
params:
"%rpname%" : { get_param: replica_name }
"%master%": { get_attr: [ master, first_address ] }
"%privkey%": { get_attr: [ master_privkey_wait_condition, data ] }
"%pubkey%": { get_attr: [ master_pubkey_wait_condition, data ] }
"%name%": { list_join: [ '-', [{ get_param: 'OS::stack_name' },'secondary_%index%'] ] }
"%wc_notify%": { get_attr: [secondary_wait_handle, curl_cli] }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment