Skip to content

Instantly share code, notes, and snippets.

@ianunruh
Last active August 29, 2015 14:06
Show Gist options
  • Save ianunruh/97be36c47110a78432a5 to your computer and use it in GitHub Desktop.
Save ianunruh/97be36c47110a78432a5 to your computer and use it in GitHub Desktop.
Onboard tenants to OpenStack
#!/usr/bin/env python
from argparse import ArgumentParser, RawTextHelpFormatter
import os
import sys
import keystoneclient.v2_0
import neutronclient.v2_0.client
NEUTRON_ROUTER_FORMAT = '{}-router'
NEUTRON_NETWORK_FORMAT = '{}-network'
def find_or_create_tenant(keystone, name):
for tenant in keystone.tenants.list():
if tenant.name == name:
return tenant
return keystone.tenants.create(name)
def find_role(keystone, name):
for role in keystone.roles.list():
if role.name == name:
return role
raise RuntimeError('Could not find role')
def find_or_create_user(keystone, username, password):
for user in keystone.users.list():
if user.name == username:
return user
return keystone.users.create(username, password)
def grant_role(keystone, user, role, tenant):
for r in keystone.roles.roles_for_user(user, tenant):
if r == role:
return
keystone.roles.add_user_role(user, role, tenant)
def find_external_network(neutron, name):
response = neutron.list_networks()
for network in response['networks']:
if name:
if network['name'] == name:
if not network['router:external']:
raise ValueError('Network is not an external network')
return network['id']
elif network['router:external']:
return network['id']
raise RuntimeError('Could not find suitable external network')
def find_or_create_router(neutron, name, external_network_id):
response = neutron.list_routers()
for router in response['routers']:
if router['name'] == name:
return router['id']
request = {
'router': {
'name': name,
'external_gateway_info': {
'network_id': external_network_id
}
}
}
response = neutron.create_router(request)
return response['router']['id']
def find_or_create_network(neutron, name):
response = neutron.list_networks()
for network in response['networks']:
if network['name'] == name:
return network['id']
request = {
'network': {
'name': name
}
}
response = neutron.create_network(request)
return response['network']['id']
def ensure_subnet(neutron, network_id, cidr, router_id):
response = neutron.list_subnets()
for subnet in response['subnets']:
if subnet['cidr'] == cidr:
return
request = {
'subnet': {
'network_id': network_id,
'ip_version': 4,
'cidr': cidr
}
}
response = neutron.create_subnet(request)
request = {
'subnet_id': response['subnet']['id']
}
neutron.add_interface_router(router_id, request)
def main():
parser = ArgumentParser(
usage='%(prog)s tenant',
formatter_class=RawTextHelpFormatter
)
parser.add_argument('tenant', help='Name of the tenant to create')
parser.add_argument('--role', default='Member', help='Role of the user being created')
parser.add_argument('--username', help='Username of the user being created')
parser.add_argument('--password', help='Password of the user being created')
parser.add_argument('--external-network', help='Name of the external network used as the router gateway')
parser.add_argument('--cidr', default='192.168.20.0/24', help='CIDR of the subnet being created')
parser.add_argument('--skip-network', action='store_true', help='Skip creating the network and subnet')
parser.add_argument('--os-auth-url', default=os.getenv('OS_AUTH_URL'))
parser.add_argument('--os-username', default=os.getenv('OS_USERNAME'))
parser.add_argument('--os-password', default=os.getenv('OS_PASSWORD'))
parser.add_argument('--os-tenant-name', default=os.getenv('OS_TENANT_NAME'))
args = parser.parse_args()
valid = True
if not args.os_auth_url:
print 'Keystone auth URL required (use --os-auth-url or the OS_AUTH_URL environment variable)'
valid = False
if not args.os_username:
print 'Keystone username required (use --os-username or the OS_USERNAME environment variable)'
valid = False
if not args.os_password:
print 'Keystone password required (use --os-password or the OS_PASSWORD environment variable)'
valid = False
if not args.os_tenant_name:
print 'Keystone tenant name required (use --os-tenant-name or the OS_TENANT_NAME environment variable)'
valid = False
if not valid:
print 'If you have an openrc file available, be sure that you sourced it'
return False
if not args.username:
args.username = args.tenant
if not args.password:
args.password = args.username
# Prepare the tenant and user
keystone = keystoneclient.v2_0.client.Client(
auth_url=args.os_auth_url,
tenant_name=args.os_tenant_name,
username=args.os_username,
password=args.os_password,
timeout=5,
)
# Create the tenant and user
tenant = find_or_create_tenant(keystone, args.tenant)
role = find_role(keystone, args.role)
user = find_or_create_user(keystone, args.username, args.password)
grant_role(keystone, user, role, tenant)
# Connect to the Neutron API
neutron = neutronclient.v2_0.client.Client(
auth_url=args.os_auth_url,
tenant_name=args.tenant,
username=args.username,
password=args.password,
timeout=15,
)
# Create the router
external_network_id = find_external_network(neutron, args.external_network)
router_name = NEUTRON_ROUTER_FORMAT.format(tenant.name)
router_id = find_or_create_router(neutron, router_name, external_network_id)
if args.skip_network:
return True
# Create the network and subnet
network_name = NEUTRON_NETWORK_FORMAT.format(tenant.name)
network_id = find_or_create_network(neutron, network_name)
ensure_subnet(neutron, network_id, args.cidr, router_id)
return True
if __name__ == '__main__':
if not main():
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment