d2e1d41cb8
Added the ability for the user of the f5 config script to override the default prefix of RPC. This is needed when multiple labs are running on the same f5. Added the ability for the user of the f5 config script to use route domains on their f5. This is used for multiple labs using the same f5 LB Change-Id: I0eba42cf3cb2419818d31c9ad2593a529fc375dc Closes-Bug: #1415994
458 lines
12 KiB
Python
Executable File
458 lines
12 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
|
|
|
|
SNAT_POOL = (
|
|
'create ltm snatpool %(prefix_name)s_SNATPOOL { members replace-all-with {'
|
|
' %(snat_pool_addresses)s%(route_domain)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%(route_domain)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%(route_domain)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%(route_domain)s/0 source-address-translation {'
|
|
' pool %(prefix_name)s_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': []
|
|
},
|
|
'swift_proxy': {
|
|
'port': 8080,
|
|
'backend_port': 8080,
|
|
'mon_type': 'http',
|
|
'group': 'swift_proxy',
|
|
'hosts': []
|
|
},
|
|
'elasticsearch': {
|
|
'port': 9200,
|
|
'backend_port': 9200,
|
|
'mon_type': 'tcp',
|
|
'group': 'elasticsearch',
|
|
'hosts': []
|
|
},
|
|
'kibana': {
|
|
'port': 8888,
|
|
'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 inventory_group is None:
|
|
return host_dict
|
|
|
|
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'
|
|
)
|
|
)
|
|
|
|
parser.add_argument(
|
|
'-r',
|
|
'--route-domain',
|
|
help="Route domain modifier."
|
|
" Default: [ %(default)s ]",
|
|
required=False,
|
|
default=''
|
|
)
|
|
|
|
parser.add_argument(
|
|
'-p',
|
|
'--prefix-name',
|
|
help="Prefix for node, pool, and virtual pools."
|
|
" Default: [ %(default)s ]",
|
|
required=False,
|
|
default='RPC'
|
|
)
|
|
|
|
return vars(parser.parse_args())
|
|
|
|
|
|
def main():
|
|
"""Run the main application."""
|
|
# Parse user args
|
|
user_args = args()
|
|
|
|
# Get prefix name
|
|
prefix_name = user_args.get('prefix_name')
|
|
|
|
# if route_domain is set, add % modifier
|
|
if user_args.get('route_domain') is not '':
|
|
user_args['route_domain'] = "%{}".format(user_args.get('route_domain'))
|
|
|
|
# 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)
|
|
|
|
# Have to override galera pool parts mont_type to match prefix
|
|
pool_parts['galera']['mon_type'] = '%s_MON_GALERA' % prefix_name
|
|
|
|
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'])
|
|
node['route_domain'] = user_args.get('route_domain')
|
|
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,
|
|
'route_domain': user_args.get('route_domain'),
|
|
'prefix_name': prefix_name
|
|
}
|
|
)
|
|
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,
|
|
'route_domain': user_args.get('route_domain')
|
|
}
|
|
|
|
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()
|