openstack-ansible/scripts/f5-config.py
2014-09-08 10:39:26 -05:00

426 lines
11 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright 2014, Rackspace US, Inc.
#
# 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.
#
# (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
import argparse
import json
import os
import netaddr
PREFIX_NAME = 'RPC'
SNAT_POOL = (
'create ltm snatpool %(prefix_name)s_SNATPOOL { members replace-all-with {'
' %(snat_pool_addresses)s } }'
)
MONITORS = (
'create ltm monitor mysql %(prefix_name)s_MON_GALERA { count 0 database'
' information_schema debug yes defaults-from mysql destination *:*'
' interval 30 time-until-up 0 timeout 91 username haproxy }'
)
NODES = (
'create ltm node %(node_name)s { address %(container_address)s }'
)
PRIORITY_ENTRY = '{ priority-group %(priority_int)s }'
POOL_NODE = {
'beginning': 'create ltm pool %(pool_name)s {'
' load-balancing-mode fastest-node members replace-all-with'
' { %(nodes)s }',
'priority': 'min-active-members 1',
'end': 'monitor %(mon_type)s }'
}
VIRTUAL_ENTRIES = (
'create ltm virtual %(vs_name)s {'
' destination %(internal_lb_vip_address)s:%(port)s'
' ip-protocol tcp mask 255.255.255.255'
' pool %(pool_name)s profiles replace-all-with { fastL4 { } }'
' source 0.0.0.0/0 source-address-translation {'
' pool RPC_SNATPOOL type snat } }'
)
# This is a dict of all groups and their respected values / requirements
POOL_PARTS = {
'galera': {
'port': 3306,
'backend_port': 3306,
'mon_type': 'RPC_MON_GALERA',
'priority': True,
'group': 'galera',
'hosts': []
},
'glance_api': {
'port': 9292,
'backend_port': 9292,
'mon_type': 'http',
'group': 'glance_api',
'hosts': []
},
'glance_registry': {
'port': 9191,
'backend_port': 9191,
'mon_type': 'http',
'group': 'glance_registry',
'hosts': []
},
'heat_api_cfn': {
'port': 8000,
'backend_port': 8000,
'mon_type': 'http',
'group': 'heat_api_cfn',
'hosts': []
},
'heat_api_cloudwatch': {
'port': 8003,
'backend_port': 8003,
'mon_type': 'http',
'group': 'heat_api_cloudwatch',
'hosts': []
},
'heat_api': {
'port': 8004,
'backend_port': 8004,
'mon_type': 'http',
'group': 'heat_api',
'hosts': []
},
'keystone_admin': {
'port': 35357,
'backend_port': 35357,
'mon_type': 'http',
'group': 'keystone',
'hosts': []
},
'keystone_service': {
'port': 5000,
'backend_port': 5000,
'mon_type': 'http',
'group': 'keystone',
'hosts': []
},
'neutron_server': {
'port': 9696,
'backend_port': 9696,
'mon_type': 'http',
'group': 'neutron_server',
'hosts': []
},
'nova_api_ec2': {
'port': 8773,
'backend_port': 8773,
'mon_type': 'http',
'group': 'nova_api_ec2',
'hosts': []
},
'nova_api_metadata': {
'port': 8775,
'backend_port': 8775,
'mon_type': 'http',
'group': 'nova_api_metadata',
'hosts': []
},
'nova_api_os_compute': {
'port': 8774,
'backend_port': 8774,
'mon_type': 'http',
'group': 'nova_api_os_compute',
'hosts': []
},
'nova_spice_console': {
'port': 6082,
'backend_port': 6082,
'mon_type': 'http',
'group': 'nova_spice_console',
'hosts': []
},
'cinder_api': {
'port': 8776,
'backend_port': 8776,
'mon_type': 'http',
'group': 'cinder_api',
'hosts': []
},
'horizon': {
'port': 80,
'backend_port': 80,
'mon_type': 'http',
'group': 'horizon',
'hosts': []
},
'horizon_ssl': {
'port': 443,
'backend_port': 443,
'mon_type': 'tcp',
'group': 'horizon',
'hosts': []
},
'memcached': {
'port': 11211,
'backend_port': 11211,
'mon_type': 'tcp',
'group': 'memcached',
'priority': True,
'limit_source': True,
'hosts': []
},
'elasticsearch': {
'port': 9200,
'backend_port': 9200,
'mon_type': 'tcp',
'group': 'elasticsearch',
'hosts': []
},
'kibana': {
'port': 8080,
'backend_port': 80,
'mon_type': 'http',
'group': 'kibana',
'priority': True,
'hosts': []
},
'kibana_ssl': {
'port': 8443,
'backend_port': 443,
'mon_type': 'tcp',
'group': 'kibana',
'priority': True,
'hosts': []
}
}
def recursive_host_get(inventory, group_name, host_dict=None):
if host_dict is None:
host_dict = {}
inventory_group = inventory.get(group_name)
if 'children' in inventory_group and inventory_group['children']:
for child in inventory_group['children']:
recursive_host_get(
inventory=inventory, group_name=child, host_dict=host_dict
)
if inventory_group.get('hosts'):
for host in inventory_group['hosts']:
if host not in host_dict['hosts']:
ca = inventory['_meta']['hostvars'][host]['container_address']
node = {
'hostname': host,
'container_address': ca
}
host_dict['hosts'].append(node)
return host_dict
def build_pool_parts(inventory):
for key, value in POOL_PARTS.iteritems():
recursive_host_get(
inventory, group_name=value['group'], host_dict=value
)
return POOL_PARTS
def file_find(filename, user_file=None, pass_exception=False):
"""Return the path to a file.
If no file is found the system will exit.
The file lookup will be done in the following directories:
/etc/rpc_deploy/
$HOME/rpc_deploy/
$(pwd)/rpc_deploy/
:param filename: ``str`` Name of the file to find
:param user_file: ``str`` Additional localtion to look in FIRST for a file
"""
file_check = [
os.path.join(
'/etc', 'rpc_deploy', filename
),
os.path.join(
os.environ.get('HOME'), 'rpc_deploy', filename
),
os.path.join(
os.getcwd(), filename
)
]
if user_file is not None:
file_check.insert(0, os.path.expanduser(user_file))
for f in file_check:
if os.path.isfile(f):
return f
else:
if pass_exception is False:
raise SystemExit('No file found at: %s' % file_check)
else:
return False
def args():
"""Setup argument Parsing."""
parser = argparse.ArgumentParser(
usage='%(prog)s',
description='Rackspace Openstack, Inventory Generator',
epilog='Inventory Generator Licensed "Apache 2.0"')
parser.add_argument(
'-f',
'--file',
help='Inventory file. Default: [ %(default)s ]',
required=False,
default='rpc_inventory.json'
)
parser.add_argument(
'-s',
'--snat-pool-address',
help='LB Main SNAT pool address for [ RPC_SNATPOOL ], for'
' multiple snat pool addresses comma seperate the ip'
' addresses. By default this IP will be .15 from within your'
' containers_cidr as found within inventory.',
required=False,
default=None
)
parser.add_argument(
'--limit-source',
help='Limit available connections to the source IP for all source'
' limited entries.',
required=False,
default=None
)
parser.add_argument(
'-e',
'--export',
help='Export the generated F5 configuration script.'
' Default: [ %(default)s ]',
required=False,
default=os.path.join(
os.path.expanduser('~/'), 'rpc_f5_config.sh'
)
)
return vars(parser.parse_args())
def main():
"""Run the main application."""
# Parse user args
user_args = args()
# Get the contents of the system environment json
environment_file = file_find(filename=user_args['file'])
with open(environment_file, 'rb') as f:
inventory_json = json.loads(f.read())
nodes = []
pools = []
virts = []
pool_parts = build_pool_parts(inventory=inventory_json)
lb_vip_address = inventory_json['all']['vars']['internal_lb_vip_address']
for key, value in pool_parts.iteritems():
value['group_name'] = key.upper()
value['vs_name'] = '%s_VS_%s' % (
PREFIX_NAME, value['group_name']
)
value['pool_name'] = '%s_POOL_%s' % (
PREFIX_NAME, value['group_name']
)
node_data = []
priority = 100
for node in value['hosts']:
node['node_name'] = '%s_NODE_%s' % (PREFIX_NAME, node['hostname'])
nodes.append('%s\n' % NODES % node)
virt = (
'%s\n' % VIRTUAL_ENTRIES % {
'port': value['port'],
'vs_name': value['vs_name'],
'pool_name': value['pool_name'],
'internal_lb_vip_address': lb_vip_address
}
)
if virt not in virts:
virts.append(virt)
if value.get('priority') is True:
node_data.append(
'%s:%s %s' % (
node['node_name'],
value['backend_port'],
PRIORITY_ENTRY % {'priority_int': priority}
)
)
priority -= 5
else:
node_data.append(
'%s:%s' % (
node['node_name'],
value['backend_port']
)
)
value['nodes'] = ' '.join(node_data)
pool_node = [POOL_NODE['beginning'] % value]
if value.get('priority') is True:
pool_node.append(POOL_NODE['priority'])
pool_node.append(POOL_NODE['end'] % value)
pools.append('%s\n' % ' '.join(pool_node))
# define the SNAT pool address
snat_pool_adds = user_args.get('snat_pool_address')
if snat_pool_adds is None:
container_cidr = inventory_json['all']['vars']['container_cidr']
network = netaddr.IPNetwork(container_cidr)
snat_pool_adds = str(network[15])
snat_pool_addresses = ' '.join(snat_pool_adds.split(','))
snat_pool = '%s\n' % SNAT_POOL % {
'prefix_name': PREFIX_NAME,
'snat_pool_addresses': snat_pool_addresses
}
script = [
'#!/usr/bin/bash\n',
snat_pool,
'%s\n' % MONITORS % {'prefix_name': PREFIX_NAME}
]
script.extend(nodes)
script.extend(pools)
script.extend(virts)
with open(user_args['export'], 'wb') as f:
f.writelines(script)
if __name__ == "__main__":
main()