Updating to handle unicode in python 2 and 3$

added retry with backoff for the SSL cert to show up after it is added (CAP, ftw)$
This commit is contained in:
Jeremy Heffner 2015-08-24 16:17:04 -07:00
parent 09bc79ef84
commit d599aaa410
1 changed files with 44 additions and 37 deletions

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals # at top of module
import os import os
import sys import sys
import base64 import base64
@ -480,18 +482,18 @@ def unlock(path=None):
class ProvisionELB(Command): class ProvisionELB(Command):
""" """
Creates and provisions a certificate on an ELB based on a json blob Creates and provisions a certificate on an ELB based on command line arguments
""" """
option_list = ( option_list = (
Option('-d', '--dns', dest='dns', required=True), Option('-d', '--dns', dest='dns', action='append', required=True, type=unicode),
Option('-e', '--elb', dest='elb', required=True), Option('-e', '--elb', dest='elb_name', required=True, type=unicode),
Option('-o', '--owner', dest='owner'), Option('-o', '--owner', dest='owner', type=unicode),
Option('-a', '--authority', dest='authority', required=True), Option('-a', '--authority', dest='authority', required=True, type=unicode),
Option('-s', '--description', dest='description', default=u'Command line provisioned keypair'), Option('-s', '--description', dest='description', default=u'Command line provisioned keypair', type=unicode),
Option('-t', '--destinations', dest='destinations'), Option('-t', '--destinations', dest='destinations', action='append', type=unicode),
Option('-n', '--notifications', dest='notifications'), Option('-n', '--notifications', dest='notifications', action='append', type=unicode, default=[]),
Option('-r', '--region', dest='region', default=u'us-east-1'), Option('-r', '--region', dest='region', default=u'us-east-1', type=unicode),
Option('-p', '--dport', '--port', dest='dport', default=7002), Option('-p', '--dport', '--port', dest='dport', default=7002),
Option('--src-port', '--source-port', '--sport', dest='sport', default=443) Option('--src-port', '--source-port', '--sport', dest='sport', default=443)
) )
@ -506,42 +508,35 @@ class ProvisionELB(Command):
if not g.user: if not g.user:
g.user = lemur.users.service.get_all()[0] g.user = lemur.users.service.get_all()[0]
return unicode(g.user.username) return g.user.username
def build_cert_options(self, destinations, notifications, description, owner, dns, authority): def build_cert_options(self, destinations, notifications, description, owner, dns, authority):
# convert argument lists to arrays, or empty sets from lemur.certificates.views import valid_authority
destinations = [] if not destinations else self._get_destinations(destinations.split(','))
notifications = [] if not notifications else notifications.split(',')
dns = dns.split(',') # convert argument lists to arrays, or empty sets
destinations = self.get_destinations(destinations)
# get the primary CN # get the primary CN
commonName = unicode(dns.pop(0)) common_name = dns[0]
# If there are more than one fqdn, add them as alternate names # If there are more than one fqdn, add them as alternate names
extensions = {} extensions = {}
if dns: if len(dns) > 1:
sub_alt_names = [] extensions['subAltNames'] = {'names': map(lambda x: {'nameType': 'DNSName', 'value': x}, dns)}
for alt_name in dns[1:]:
sub_alt_names.append({'nameType': 'DNSName', 'value': unicode(alt_name)})
extensions['subAltNames'] = {'names': sub_alt_names}
from lemur.certificates.views import valid_authority
authority = valid_authority({"name": authority}) authority = valid_authority({"name": authority})
options = { options = {
# Convert from the Destination model to the JSON input expected further in the code
'destinations': map(lambda x: {'id': x.id, 'label': x.label}, destinations), 'destinations': map(lambda x: {'id': x.id, 'label': x.label}, destinations),
'description': unicode(description), 'description': description,
'notifications': notifications, 'notifications': notifications,
'commonName': commonName, 'commonName': common_name,
'extensions': extensions, 'extensions': extensions,
'authority': authority, 'authority': authority,
'owner': owner, 'owner': owner,
# defaults: # defaults:
'organization': u'Netflix', 'organization': u'Netflix, Inc.',
'organizationalUnit': u'Operations', 'organizationalUnit': u'Operations',
'country': u'US', 'country': u'US',
'state': u'California', 'state': u'California',
@ -556,17 +551,15 @@ class ProvisionELB(Command):
destinations = [] destinations = []
for destination_name in destination_names: for destination_name in destination_names:
sys.stderr.write("looking up dest: {}\n".format(destination_name))
destinations.append(service.get_by_label(destination_name)) destinations.append(service.get_by_label(destination_name))
return destinations return destinations
def _get_destination_account(self, destinations): def get_destination_account(self, destinations):
for destination in self._get_destinations(destinations.split(',')): for destination in self.get_destinations(destinations):
if destination.plugin_name == 'aws-destination': if destination.plugin_name == 'aws-destination':
account_number = destination.plugin.get_option('accountNumber', destination.options) account_number = destination.plugin.get_option('accountNumber', destination.options)
sys.stdout.write('found aws account: {}\n'.format(account_number))
return account_number return account_number
sys.stderr.write("No destination AWS account provided, failing\n") sys.stderr.write("No destination AWS account provided, failing\n")
@ -575,6 +568,7 @@ class ProvisionELB(Command):
def run(self, dns, elb_name, owner, authority, description, notifications, destinations, region, dport, sport): def run(self, dns, elb_name, owner, authority, description, notifications, destinations, region, dport, sport):
from lemur.certificates import service from lemur.certificates import service
from lemur.plugins.lemur_aws import elb from lemur.plugins.lemur_aws import elb
from boto.exception import BotoServerError
# configure the owner if we can find it, or go for default, and put it in the global # configure the owner if we can find it, or go for default, and put it in the global
owner = self.configure_user(owner) owner = self.configure_user(owner)
@ -591,18 +585,31 @@ class ProvisionELB(Command):
aws_account = self.get_destination_account(destinations) aws_account = self.get_destination_account(destinations)
# create the certificate # create the certificate
sys.stdout.write('Creating certificate for {}'.format(cert_options['commonName'])) sys.stdout.write('Creating certificate for {}\n'.format(cert_options['commonName']))
cert = service.create(**cert_options) cert = service.create(**cert_options)
cert_arn = cert.get_arn(aws_account) cert_arn = cert.get_arn(aws_account)
sys.stderr.write('cert arn: {}\n'.format(cert_arn)) sys.stderr.write('cert arn: {}\n'.format(cert_arn))
time.sleep(2) sys.stderr.write('Configuring elb {} from port {} to port {} in region {} with cert {}\n'.format(elb_name, sport, dport, region, cert_arn))
# adding the listener
sys.stderr.write('Configuring elb {} from port {} to port {} in region {} with cert {}\n'.format(elb, sport, dport, region, cert_arn))
delay = 1
done = False
retries = 5
while not done and retries > 0:
try:
elb.create_new_listeners(aws_account, region, elb_name, [(sport, dport, 'HTTPS', cert_arn)]) elb.create_new_listeners(aws_account, region, elb_name, [(sport, dport, 'HTTPS', cert_arn)])
except BotoServerError as bse:
# if the server retuirns ad error, the certificate
if bse.error_code == 'CertificateNotFound':
sys.stderr.write('Certificate not available yet in the AWS account, waiting {}, {} retries left\n'.format(delay, retries))
time.sleep(delay)
delay *= 2
retries -= 1
else:
raise bse
else:
done = True
def main(): def main():