Example: Volume Automation
Explanation
This example shows off how cloud-init can be configured to spin up a custom LAMP server. Additionally, this example shows how python can be incorporated to use cloud services API to create and attach a volume. Each section broken down follows.
timezone:
timezone: quickly sets the locale of this instance
bootcmd:
Looking at https://stackoverflow.com/questions/34095839/cloud-init-what-is-the-execution-order-of-cloud-config-directives , bootcmd is the third module ran and commands listed here are ran every boot, instead of running during the instance initialization. The command in the example is disabling SELinux for the current session. Disabling SELinux via its configuration file requires a reboot
package_upgrade:
As discussed in Automate System Patches, this variable, when true, updates the OS via yum update or apt-get update && apt-get upgrade
packages:
As discussed in Automate System Patches, this list of packages is installed via yum install or apt-get install
users:
As discussed in Automate System Patches, the users section of the configuration file creates the user and sets user permissions
runcmd:
Looking at https://stackoverflow.com/questions/34095839/cloud-init-what-is-the-execution-order-of-cloud-config-directives runcmd is ran much later in the initialization process. So any files written via cloud-init can be ran here.
This tutorial adds a php repo, and yum installs a newer php and python release. The commands go on to start and enable services, unzip the application that will be running on this machine, change ownership of directories, add httpd rules to the firewall, run sql scripts that are written in the latter part of this example, and change python environments to run the volume create and attach script.
write_files:
This section is where files can be written by providing first the desired path of the file, and then providing the files’ contents.
‘sqlinit.sh’ is writing commands to mariadb, mimicking the mysql_secure_installation script. ‘Sqlnextcloud.sh’ writes commands to create the database for the main application ran on this instance.
‘attachcreate.py’ first connects to the api using the ec2 access and secret keys generated via the webUI. Then the client object calls the create_volume method with a few parameters, then ID of the current instance is requested, and then the volume is attached via the attach_volume method.
The volume is ready to be formatted, mounted, and fstab will need to edited. As a challenge, include those commands to the example.
Configuration Example
#cloud-config
timezone: US/Central
bootcmd:
- setenforce 0
package_upgrade: True
packages:
- wget
- epel-release
- httpd
- git
- vim
- yum-utils
- bzip2
- mariadb-server
- mariadb
- samba-client
users:
- name: demo
ssh-authorized-keys:
- ssh-rsa sshkey1line
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups: wheel
shell: /bin/bash
runcmd:
- rpm -Uvh http://rpms.remirepo.net/enterprise/remi-release-7.rpm
- yum-config-manager --enable remi-php70
- yum -y install php php-mysql php-pecl-zip php-xml php-mbstring php-gd php-smbclient https://centos7.iuscommunity.org/ius-release.rpm
- yum -y install python36u
- yum install python36u-pip
- yum install python36u-devel
- systemctl start httpd; systemctl enable httpd
- systemctl start mariadb; systemctl enable mariadb
- wget https://download.nextcloud.com/server/releases/nextcloud-12.0.3.tar.bz2
- tar -jxpvf nextcloud-12.0.3.tar.bz2 -C /var/www/html/
- chown -R apache:apache /var/www/html/nextcloud
- firewall-cmd --permanent --zone=public --add-service=http
- firewall-cmd --permanent --zone=public --add-service=https
- firewall-cmd --reload
- chmod u+x /sqlinit.sh /sqlnextcloud.sh
- /./sqlinit.sh
- /./sqlnextcloud.sh
- mkdir /awsapi
- cd /awsapi
- python3.6 -m venv awsapi
- source awsapi/bin/activate
- pip install awscli boto3 requests
- python /attachcreate.py
write_files:
- path: /sqlinit.sh
content: |
#!/bin/bash
mysqladmin -u root password "root"
mysql -u root -p"root" -e "UPDATE mysql.user SET Password=PASSWORD('root') WHERE User='root'"
mysql -u root -p"root" -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"
mysql -u root -p"root" -e "DELETE FROM mysql.user WHERE User=''"
mysql -u root -p"root" -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'"
mysql -u root -p"root" -e "FLUSH PRIVILEGES"
- path: /sqlnextcloud.sh
content: |
#!/bin/bash
mysql -u root -p"root" -e "create database nextcloud"
mysql -u root -p"root" -e "grant all on nextcloud.* to 'nextcloud'@'localhost' identified by 'nextcloud'"
mysql -u root -p"root" -e "FLUSH PRIVILEGES"
- path: /attachcreate.py
content: |
import boto3
import sys
import requests
class Connection:
def __init__(self):
self.client = boto3.Session.client(boto3.session.Session(), service_name="ec2", region_name="symphony",
endpoint_url="https://198.199.56.210/api/v2/ec2/",
verify=False,
aws_access_key_id="123456789abc",
aws_secret_access_key="zxyabc987654321")
def createattachVol(self):
vol = self.client.create_volume(Size=100,AvailabilityZone='symphony')
response = requests.get('http://169.254.169.254/latest/meta-data/instance-id')
instance_id = response.text
attach_resp = self.client.attach_volume(
VolumeId=vol['VolumeId'],
InstanceId=instance_id,
Device='/dev/sdm'
)
def testID(self):
instances = self.client.describe_instances()
expectedID = requests.get('http://169.254.169.254/latest/meta-data/instance-id').text
for row in instances['Reservations']:
if row['Instances'][0]['InstanceId'] == expectedID:
return True
if __name__ == "__main__":
client = Connection()
if client.testID():
client.createattachVol()