...
Code Block |
---|
language | yml |
---|
title | Common Infrastructurecommon.yaml |
---|
linenumbers | true |
---|
collapse | true |
---|
|
heat_template_version: 2018-08-31
description: >
A template to create common base infrastructure for the heat-guide at
https://www.ntnu.no/wiki/display/skyhigh/Openstack+Heat
resources:
network:
type: OS::Neutron::Net
subnet_v4:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: network }
cidr: '192.168.0.0/24'
dns_nameservers: [ '129.241.0.200', '129.241.0.201' ]
ip_version: 4
router:
type: OS::Neutron::Router
properties:
external_gateway_info: { network: ntnu-internal }
router_interface_v4:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: router }
subnet: { get_resource: subnet_v4 }
secgroup_generic:
type: OS::Neutron::SecurityGroup
properties:
description: |
A security group allowing users connect to the VM's using ssh
rules:
- protocol: icmp
remote_ip_prefix: '0.0.0.0/0'
- protocol: tcp
port_range_min: 22
port_range_max: 22
remote_ip_prefix: '0.0.0.0/0'
- protocol: tcp
remote_ip_prefix: '192.168.0.0/24'
port_range_min: 111
port_range_max: 111
- protocol: udp
remote_ip_prefix: '192.168.0.0/24'
port_range_min: 111
port_range_max: 111
- protocol: tcp
remote_ip_prefix: '192.168.0.0/24'
port_range_min: 2049
port_range_max: 2049
- protocol: udp
remote_ip_prefix: '192.168.0.0/24'
port_range_min: 2049
port_range_max: 2049
- protocol: tcp
remote_ip_prefix: '192.168.0.0/24'
port_range_min: 32767
port_range_max: 32768
- protocol: udp
remote_ip_prefix: '192.168.0.0/24'
port_range_min: 32767
port_range_max: 32768
outputs:
network:
description: The network created by the template
value: { get_resource: network }
secgroup_generic:
description: The security-group allowing generiv VM access.
value: { get_resource: secgroup_generic } |
...
Code Block |
---|
language | yml |
---|
title | Common InfrastructureHeat Parameters |
---|
linenumbers | true |
---|
collapse | true |
---|
|
parameters:
flavor:
type: string
label: Fileserver flavor
description: The flavor used to spawn the fileserver
constraints:
- custom_constraint: nova.flavor
ubuntu:
type: string
label: Fileserver image
description: The image used to spawn the fileserver
constraints:
- custom_constraint: glance.image
admin-ssh-key:
type: string
label: SSH Key admin
description: The SSH-key to inject in the fileserver for admin-purposes.
user-ssh-key:
type: string
label: SSH Key User
description: The SSH-key to inject in the fileserver for the user user.
secgroup_generic:
type: string
network:
type: string
volume_type:
type: string
label: Volume type
description: The cinder-type used to create the volume for the fileserver
default: 'HDD-300'
constraints:
- custom_constraint: cinder.vtype
volume_size:
type: number
label: Volume size
default: 2
description: The size of the exported volume from the fileserver |
...
- flavor: An openstack flavor defining the specifications for the two virtual machines we are going to make
- ubuntu: The ID of the openstack-image which we are using to create our VM's
- admin-ssh-key: An ssh-key to be injected into the "administrator" user of the machines
- user-ssh-key: An ssh-key to be injected into the "user" user of the machines
- secgroup_generic: The ID of the security-group to use
- network: The ID of the network to connect the machines to
- volume_type: The name of the Openstack volume type to use. This one defaults to "HDD-300", and you do not need to specify it unless you want another type.
- volume_size: The size og the volume attached to the fileserver. This one defaults to "2", an you do not need to specify it unless you want another size.
Defining the fileserver VM
Creating the fileserver VM is going to need a couple of resources:
- A cloud-config snippet creating the users and injecting the ssh-keys
- A cloud-config snippet installing the nfs-server packages, creating the /etc/exports file and formatting the extra disk.
- A shell-script altering the NFS-server configuration, and mounting the extra disk.
- A floating IP
- A virtual server
- A volume
The configuration-snippets and shellscript can be defined as three seperate resources, and then joined together to a single resource which can be given to a VM like so:
Code Block |
---|
language | yml |
---|
title | Cloud-conifg and scripts |
---|
linenumbers | true |
---|
collapse | true |
---|
|
cloudconf_fileserver:
type: OS::Heat::MultipartMime
properties:
parts:
- config: {get_resource: cloudconf_base}
- config: {get_resource: cloudconf_fileservers}
- config: {get_resource: script_fileserver}
cloudconf_base:
type: OS::Heat::CloudConfig
properties:
cloud_config:
package_update: true
package_upgrade: true
timezone: "Europe/Oslo"
users:
- name: administrator
sudo: ALL=(ALL) NOPASSWD:ALL
lock_passwd: True
shell: /bin/bash
ssh_authorized_keys:
- { get_param: admin-ssh-key }
- name: user
lock_passwd: True
shell: /bin/bash
ssh_authorized_keys:
- { get_param: user-ssh-key }
power_state:
mode: 'reboot'
message: 'Reboots after installing'
condition: True
cloudconf_fileservers:
type: OS::Heat::CloudConfig
properties:
cloud_config:
packages:
- 'nfs-kernel-server'
- 'pwgen'
write_files:
- content: '/opt/data/shared 192.168.0.0/24(rw,sync,no_subtree_check)'
path: '/etc/exports'
- content: |
options lockd nlm_udpport=32768 nlm_tcpport=32768
options nfs callback_tcpport=32764
path: '/etc/modprobe.d/local.conf'
disk_setup:
/dev/vdb:
table_type: gpt
layout: true
overwrite: false
fs_setup:
- filesystem: 'ext4'
label: 'datapartition'
device: '/dev/vdb'
partition: 'auto'
script_fileserver:
type: OS::Heat::SoftwareConfig
properties:
group: ungrouped
config: |
#!/bin/bash
# Restrict NFS ports
sed -i -r 's/STATDOPTS=.*/STATDOPTS="--port 32765 --outgoing-port 32766"/' /etc/default/nfs-common
sed -i -r 's/RPCMOUNTDOPTS=.*/RPCMOUNTDOPTS="-p 32767"/' /etc/default/nfs-kernel-server
# Mount disks
echo "/dev/vdb1 /opt/data ext4 defaults,comment=cloudconfig 0 0" >> /etc/fstab
mkdir /opt/data
mount /dev/vdb1 /opt/data
mkdir /opt/data/shared
chown user:user /opt/data/shared |
The next part is to create the fileserver, and the floating IP to attach to it. For some reason Heat does not let us add floating IP's to servers, but we are allowed to add it to ports which can be attached to the servers. So, creating a server with a floating IP requires three resources: a server, an IP and an IP attachment. The server also uses the "cloudconf_fileserver" resource created above, and it gets a custom hostname set which is "STACK-fileserver" where we replace "STACK" with the name of the stack when it is created. The port we attach to the server gets both an floating IP and the security-group.
Code Block |
---|
language | yml |
---|
title | Fileserver with floating IP |
---|
linenumbers | true |
---|
collapse | true |
---|
|
fileserver:
type: OS::Nova::Server
properties:
name:
str_replace:
template: 'STACK-fileserver'
params:
STACK: { get_param: OS::stack_name }
image: { get_param: ubuntu }
flavor: { get_param: flavor }
networks:
- {"port": { get_resource: fileserver_port }}
user_data_format: RAW
user_data: { get_resource: cloudconf_fileserver }
fileserver_port:
type: OS::Neutron::Port
properties:
admin_state_up: true
network_id: { get_param: network }
security_groups: [{ get_param: secgroup_generic }]
fileserver_floatingip:
type: OS::Neutron::FloatingIP
properties:
floating_network: 'ntnu-internal'
port_id: { get_resource: fileserver_port } |
The only bits left now is creating a volume and attaching to the server:
Code Block |
---|
language | yml |
---|
title | Fileserver with floating IP |
---|
linenumbers | true |
---|
collapse | true |
---|
|
volume:
type: OS::Cinder::Volume
properties:
size: { get_param: volume_size }
volume_type: { get_param: volume_type }
volume_attach:
type: OS::Cinder::VolumeAttachment
properties:
instance_uuid: { get_resource: fileserver }
volume_id: { get_resource: volume } |
Defining the client VM
In addition to the server we want to have a client. This client uses one of the cloudconfig-snippets from the server (the one creating the users) in addition to a cloudconfig-snippet instructing the server to mount the volume. The client can be deined like so:
Code Block |
---|
language | yml |
---|
title | Fileserver with floating IP |
---|
linenumbers | true |
---|
collapse | true |
---|
|
cloudconf_nfsmount:
type: OS::Heat::CloudConfig
properties:
cloud_config:
packages:
- 'nfs-common'
write_files:
- content:
str_replace:
template: 'IP:/opt/data/shared /mnt/filserver nfs4 defaults 0 0'
params:
IP: { get_attr: [ fileserver, networks, {get_param: network}, 0 ] }
path: '/etc/fstab'
append: true
cloudconf_client:
type: OS::Heat::MultipartMime
properties:
parts:
- config: {get_resource: cloudconf_base}
- config: {get_resource: cloudconf_nfsmount}
nfsclient:
type: OS::Nova::Server
properties:
name:
str_replace:
template: 'STACK-client'
params:
STACK: { get_param: OS::stack_name }
image: { get_param: ubuntu }
flavor: { get_param: flavor }
networks:
- {"port": { get_resource: nfsclient_port }}
user_data_format: RAW
user_data: { get_resource: cloudconf_client }
nfsclient_port:
type: OS::Neutron::Port
properties:
admin_state_up: true
network_id: { get_param: network }
security_groups: [{ get_param: secgroup_generic }]
nfsclient_floatingip:
type: OS::Neutron::FloatingIP
properties:
floating_network: 'ntnu-internal'
port_id: { get_resource: nfsclient_port } |
Stitching it all together
Adding all the components for the client/server VM's together in a single file, and adding some outputs letting us easily see the IP-addresses assigned to the VM's we get a Heat-Template looking like so:
Code Block |
---|
language | yml |
---|
title | clientserver-lab.yaml |
---|
linenumbers | true |
---|
collapse | true |
---|
|
heat_template_version: 2018-08-31
description: >
This template creates, installs and configures a fileserver, serving as the
file-repository for a certain NICE2 project.
parameters:
flavor:
type: string
label: Fileserver flavor
description: The flavor used to spawn the fileserver
constraints:
- custom_constraint: nova.flavor
ubuntu:
type: string
label: Fileserver image
description: The image used to spawn the fileserver
constraints:
- custom_constraint: glance.image
admin-ssh-key:
type: string
label: SSH Key admin
description: The SSH-key to inject in the fileserver for admin-purposes.
user-ssh-key:
type: string
label: SSH Key User
description: The SSH-key to inject in the fileserver for the user user.
secgroup_generic:
type: string
network:
type: string
volume_type:
type: string
label: Volume type
description: The cinder-type used to create the volume for the fileserver
default: 'HDD-300'
constraints:
- custom_constraint: cinder.vtype
volume_size:
type: number
label: Volume size
default: 2
description: The size of the exported volume from the fileserver
resources:
fileserver:
type: OS::Nova::Server
properties:
name:
str_replace:
template: 'STACK-fileserver'
params:
STACK: { get_param: OS::stack_name }
image: { get_param: ubuntu }
flavor: { get_param: flavor }
networks:
- {"port": { get_resource: fileserver_port }}
user_data_format: RAW
user_data: { get_resource: cloudconf_fileserver }
fileserver_port:
type: OS::Neutron::Port
properties:
admin_state_up: true
network_id: { get_param: network }
security_groups: [{ get_param: secgroup_generic }]
fileserver_floatingip:
type: OS::Neutron::FloatingIP
properties:
floating_network: 'ntnu-internal'
port_id: { get_resource: fileserver_port }
volume:
type: OS::Cinder::Volume
properties:
size: { get_param: volume_size }
volume_type: { get_param: volume_type }
volume_attach:
type: OS::Cinder::VolumeAttachment
properties:
instance_uuid: { get_resource: fileserver }
volume_id: { get_resource: volume }
cloudconf_fileserver:
type: OS::Heat::MultipartMime
properties:
parts:
- config: {get_resource: cloudconf_base}
- config: {get_resource: cloudconf_fileservers}
- config: {get_resource: script_fileserver}
cloudconf_base:
type: OS::Heat::CloudConfig
properties:
cloud_config:
package_update: true
package_upgrade: true
timezone: "Europe/Oslo"
users:
- name: administrator
sudo: ALL=(ALL) NOPASSWD:ALL
lock_passwd: True
shell: /bin/bash
ssh_authorized_keys:
- { get_param: admin-ssh-key }
- name: user
lock_passwd: True
shell: /bin/bash
ssh_authorized_keys:
- { get_param: user-ssh-key }
power_state:
mode: 'reboot'
message: 'Reboots after installing'
condition: True
cloudconf_fileservers:
type: OS::Heat::CloudConfig
properties:
cloud_config:
packages:
- 'nfs-kernel-server'
- 'pwgen'
write_files:
- content: '/opt/data/shared 192.168.0.0/24(rw,sync,no_subtree_check)'
path: '/etc/exports'
- content: |
options lockd nlm_udpport=32768 nlm_tcpport=32768
options nfs callback_tcpport=32764
path: '/etc/modprobe.d/local.conf'
disk_setup:
/dev/vdb:
table_type: gpt
layout: true
overwrite: false
fs_setup:
- filesystem: 'ext4'
label: 'datapartition'
device: '/dev/vdb'
partition: 'auto'
script_fileserver:
type: OS::Heat::SoftwareConfig
properties:
group: ungrouped
config: |
#!/bin/bash
# Restrict NFS ports
sed -i -r 's/STATDOPTS=.*/STATDOPTS="--port 32765 --outgoing-port 32766"/' /etc/default/nfs-common
sed -i -r 's/RPCMOUNTDOPTS=.*/RPCMOUNTDOPTS="-p 32767"/' /etc/default/nfs-kernel-server
# Mount disks
echo "/dev/vdb1 /opt/data ext4 defaults,comment=cloudconfig 0 0" >> /etc/fstab
mkdir /opt/data
mount /dev/vdb1 /opt/data
mkdir /opt/data/shared
chown user:user /opt/data/shared
cloudconf_nfsmount:
type: OS::Heat::CloudConfig
properties:
cloud_config:
packages:
- 'nfs-common'
write_files:
- content:
str_replace:
template: 'IP:/opt/data/shared /mnt/filserver nfs4 defaults 0 0'
params:
IP: { get_attr: [ fileserver, networks, {get_param: network}, 0 ] }
path: '/etc/fstab'
append: true
cloudconf_client:
type: OS::Heat::MultipartMime
properties:
parts:
- config: {get_resource: cloudconf_base}
- config: {get_resource: cloudconf_nfsmount}
nfsclient:
type: OS::Nova::Server
properties:
name:
str_replace:
template: 'STACK-client'
params:
STACK: { get_param: OS::stack_name }
image: { get_param: ubuntu }
flavor: { get_param: flavor }
networks:
- {"port": { get_resource: nfsclient_port }}
user_data_format: RAW
user_data: { get_resource: cloudconf_client }
nfsclient_port:
type: OS::Neutron::Port
properties:
admin_state_up: true
network_id: { get_param: network }
security_groups: [{ get_param: secgroup_generic }]
nfsclient_floatingip:
type: OS::Neutron::FloatingIP
properties:
floating_network: 'ntnu-internal'
port_id: { get_resource: nfsclient_port }
outputs:
fileserver_address:
description: Fileserver address
value: { get_attr: [ fileserver_floatingip, fixed_ip_address ] }
fileserver_floating_address:
description: Fileserver floating IP address
value: { get_attr: [ fileserver_floatingip, floating_ip_address ] }
client_address:
description: Client address
value: { get_attr: [ nfsclient_floatingip, fixed_ip_address ] }
client_floating_address:
description: Client floating IP address
value: { get_attr: [ nfsclient_floatingip, floating_ip_address ] } |