Merge lp:~mhall119/awstrial/add-logging into lp:~newz/awstrial/logging-tests

Proposed by Michael Hall
Status: Merged
Merged at revision: 267
Proposed branch: lp:~mhall119/awstrial/add-logging
Merge into: lp:~newz/awstrial/logging-tests
Diff against target: 400 lines (+142/-38)
11 files modified
awstrial/templates/404.html (+8/-2)
awstrial/templates/500.html (+7/-1)
awstrial/templates/503.html (+24/-2)
awstrial/templates/cloud-init/byobu-countdown (+3/-8)
awstrial/templates/cloud-init/info-callback (+6/-1)
awstrial/templates/contacts.html (+1/-1)
awstrial/templates/instance.html (+1/-1)
awstrial/trial/auth.py (+4/-3)
awstrial/trial/ec2_helper.py (+10/-11)
awstrial/trial/tests.py (+77/-6)
awstrial/trial/views.py (+1/-2)
To merge this branch: bzr merge lp:~mhall119/awstrial/add-logging
Reviewer Review Type Date Requested Status
Matthew Nuzum Pending
Review via email: mp+80013@code.launchpad.net

Description of the change

Mock out DNS.DnsRequest().req() to immitate a tor exit node match or not

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'awstrial/templates/404.html'
--- awstrial/templates/404.html 2011-10-04 15:26:38 +0000
+++ awstrial/templates/404.html 2011-10-20 23:51:23 +0000
@@ -9,6 +9,12 @@
9{% endwith %}9{% endwith %}
10{% endblock %}10{% endblock %}
1111
12{% block logo_img %}
13{% with '/ubuntu-website/media' as ubuntu_website_media %}
14{{ block.super }}
15{% endwith %}
16{% endblock %}
17
12{% block extrahead %}18{% block extrahead %}
13{% with '/media' as MEDIA_URL %}19{% with '/media' as MEDIA_URL %}
14{{ block.super }}20{{ block.super }}
@@ -18,6 +24,6 @@
1824
1925
20{% block content %}26{% block content %}
21<h3>Oops!</h3>27<h2>404</h2>
22<p>This page could not be found (404)</p>28<p>This page could not be found</p>
23{% endblock %}29{% endblock %}
2430
=== modified file 'awstrial/templates/500.html'
--- awstrial/templates/500.html 2011-10-04 15:26:38 +0000
+++ awstrial/templates/500.html 2011-10-20 23:51:23 +0000
@@ -9,6 +9,12 @@
9{% endwith %}9{% endwith %}
10{% endblock %}10{% endblock %}
1111
12{% block logo_img %}
13{% with '/ubuntu-website/media' as ubuntu_website_media %}
14{{ block.super }}
15{% endwith %}
16{% endblock %}
17
12{% block extrahead %}18{% block extrahead %}
13{% with '/media' as MEDIA_URL %}19{% with '/media' as MEDIA_URL %}
14{{ block.super }}20{{ block.super }}
@@ -17,6 +23,6 @@
17{% block main_nav_links %}{% endblock %}23{% block main_nav_links %}{% endblock %}
1824
19{% block content %}25{% block content %}
20<h3>Oops!</h3>26<h2>500</h2>
21<p>It seems an error has been encountered, we have been informed. Please try again later.</p>27<p>It seems an error has been encountered, we have been informed. Please try again later.</p>
22{% endblock %}28{% endblock %}
2329
=== modified file 'awstrial/templates/503.html'
--- awstrial/templates/503.html 2011-09-15 15:20:29 +0000
+++ awstrial/templates/503.html 2011-10-20 23:51:23 +0000
@@ -1,7 +1,29 @@
1{% extends "base.html" %}1{% extends "base.html" %}
2{% block header %}2
3
4{% block title %}Error | Try Ubuntu Cloud Guest{% endblock %}
5
6{% block defaulthead %}
7{% with '/ubuntu-website/media' as ubuntu_website_media %}
8{{ block.super }}
9{% endwith %}
10{% endblock %}
11
12{% block logo_img %}
13{% with '/ubuntu-website/media' as ubuntu_website_media %}
14{{ block.super }}
15{% endwith %}
16{% endblock %}
17
18{% block extrahead %}
19{% with '/media' as MEDIA_URL %}
20{{ block.super }}
21{% endwith %}
3<meta http-equiv="REFRESH" content="0;url=http://ubuntu.com/cloud"></HEAD>22<meta http-equiv="REFRESH" content="0;url=http://ubuntu.com/cloud"></HEAD>
4{% endblock %}23{% endblock %}
24{% block main_nav_links %}{% endblock %}
25
5{% block content %}26{% block content %}
6<h1>There was an error fulfilling the request at this time. Please try again later.</h1>27<h2>503</h2>
28<p>There was an error fulfilling the request at this time. Please try again later.</p>
7{% endblock %}29{% endblock %}
830
=== renamed file 'awstrial/templates/cloud-init/byobu-enable' => 'awstrial/templates/cloud-init/byobu-countdown'
--- awstrial/templates/cloud-init/byobu-enable 2010-09-30 12:58:03 +0000
+++ awstrial/templates/cloud-init/byobu-countdown 2011-10-20 23:51:23 +0000
@@ -1,14 +1,9 @@
1#!/bin/sh1#!/bin/sh
2#sudo -Hu ubuntu byobu-launcher-install # single user2
3sem="/var/lib/cloud/sem/byobu-enable.${INSTANCE_ID}"3sem="/var/lib/cloud/sem/byobu-countdown.${INSTANCE_ID}"
4[ -e "${sem}" ] && exit 04[ -e "${sem}" ] && exit 0
55
6debconf-set-selections <<EOF6# Add AWSTrial countdown widget only for 'ubuntu' user
7byobu byobu/launch-by-default boolean true
8EOF
9dpkg-reconfigure byobu --frontend=noninteractive
10
11# above does it for all users, but below is only for 'ubuntu' user
12sudo -Hu ubuntu sh -c 'mkdir -p ~/.byobu/bin/ &&7sudo -Hu ubuntu sh -c 'mkdir -p ~/.byobu/bin/ &&
13 cat > ~/.byobu/bin/1_countdown && chmod +x ~/.byobu/bin/1_countdown' <<"EOF"8 cat > ~/.byobu/bin/1_countdown && chmod +x ~/.byobu/bin/1_countdown' <<"EOF"
14#!/bin/sh9#!/bin/sh
1510
=== modified file 'awstrial/templates/cloud-init/info-callback'
--- awstrial/templates/cloud-init/info-callback 2011-10-18 13:58:40 +0000
+++ awstrial/templates/cloud-init/info-callback 2011-10-20 23:51:23 +0000
@@ -6,9 +6,14 @@
6CALLBACK_URL="{{ callback_url }}"6CALLBACK_URL="{{ callback_url }}"
77
8mdurl="http://169.254.169.254/2009-04-04/meta-data/%s"8mdurl="http://169.254.169.254/2009-04-04/meta-data/%s"
9
9dumpk="""10dumpk="""
10hn=$1; set -e; f=$(mktemp); trap "rm -f '$f'" EXIT;11hn=$1; set -e; f=$(mktemp); trap "rm -f '$f'" EXIT;
11ssh-keyscan -t rsa,dsa localhost 2>/dev/null > "$f"12rkeys="rsa,dsa"; [ -f "/etc/ssh/ssh_host_ecdsa_key" ] && rkeys="$rkeys,ecdsa"
13{% if debug %}
14echo "Requesting fingerprints for: $rkeys" >> /var/log/instance-testing
15{% endif %}
16ssh-keyscan -t "$rkeys" localhost 2>/dev/null > "$f"
12[ -n "${hn}" ] && sed -i "s,localhost,${hn}," "$f"17[ -n "${hn}" ] && sed -i "s,localhost,${hn}," "$f"
13ssh-keygen -lf "$f"18ssh-keygen -lf "$f"
14"""19"""
1520
=== modified file 'awstrial/templates/contacts.html'
--- awstrial/templates/contacts.html 2011-10-04 15:26:38 +0000
+++ awstrial/templates/contacts.html 2011-10-20 23:51:23 +0000
@@ -14,7 +14,7 @@
14 <p>We will give you the hostname and you can SSH directly to the instance with your public SSH key on file in <a href=http://launchpad.net>Launchpad</a>. You will have full <a href=https://help.ubuntu.com/community/RootSudo>sudo (root) access</a>, so take it for an hour-long joyride, install applications, configure services, test your programs, and evaluate the overall experience. We will terminate and clean up the instance automatically within an hour.</p>14 <p>We will give you the hostname and you can SSH directly to the instance with your public SSH key on file in <a href=http://launchpad.net>Launchpad</a>. You will have full <a href=https://help.ubuntu.com/community/RootSudo>sudo (root) access</a>, so take it for an hour-long joyride, install applications, configure services, test your programs, and evaluate the overall experience. We will terminate and clean up the instance automatically within an hour.</p>
1515
16 {% if set_password %}16 {% if set_password %}
17 <p><em>You do not have ssh keys on file in your launchpad account. We strongly recommend you follow the documentation mentioned above and add keys to your launchpad account. Ssh key authentication is much more secure than password authentication. However, if you would like to launch an instance without using ssh keys, you may do so. Click 'Launch' below, and you will be generated a one-time use password and forced to change it on first login</em></p>17 <p><em>You do not have ssh keys on file in your launchpad account. We strongly recommend you follow the documentation mentioned above and add keys to your launchpad account. Ssh key authentication is much more secure than password authentication. However, if you would like to launch an instance without using ssh keys, you may do so. Click 'Launch' below, and you will be generated a random password which you can then change after login</em></p>
18 {% endif %}18 {% endif %}
19 <div id="contact" class="clearfix">19 <div id="contact" class="clearfix">
20 <div id="c_form">20 <div id="c_form">
2121
=== modified file 'awstrial/templates/instance.html'
--- awstrial/templates/instance.html 2011-10-18 13:58:40 +0000
+++ awstrial/templates/instance.html 2011-10-20 23:51:23 +0000
@@ -82,7 +82,7 @@
82 {% endif %}82 {% endif %}
83 {% else %}83 {% else %}
84 {% if instance.password %}84 {% if instance.password %}
85 <p>Your randomly generated one time password is '<b>{{ instance.password }}</b>'. You will be forced to change that on initial login.</p>85 <p>Your randomly generated one time password is '<b>{{ instance.password }}</b>'.</p>
86 {% endif %}86 {% endif %}
87 <p>You can <a href=https://help.ubuntu.com/community/SSH/OpenSSH/ConnectingTo target="_blank" >SSH</a> to your Cloud Server using:</p>87 <p>You can <a href=https://help.ubuntu.com/community/SSH/OpenSSH/ConnectingTo target="_blank" >SSH</a> to your Cloud Server using:</p>
88<pre> ssh ubuntu@{{instance.ip}}</pre>88<pre> ssh ubuntu@{{instance.ip}}</pre>
8989
=== modified file 'awstrial/trial/auth.py'
--- awstrial/trial/auth.py 2011-10-19 19:20:08 +0000
+++ awstrial/trial/auth.py 2011-10-20 23:51:23 +0000
@@ -41,8 +41,9 @@
41 if settings.USER_BLOCK_TOR_GATEWAY:41 if settings.USER_BLOCK_TOR_GATEWAY:
4242
43 DNS.ParseResolvConf()43 DNS.ParseResolvConf()
44 44
45 client = ".".join(reversed(request.META['REMOTE_ADDR'].strip().split('.')))45 remote_addr = request.META['REMOTE_ADDR']
46 client = ".".join(reversed(remote_addr.strip().split('.')))
4647
47 TARGET = ".".join(reversed(socket.gethostbyname(request.META['SERVER_NAME']).strip().split('.')))48 TARGET = ".".join(reversed(socket.gethostbyname(request.META['SERVER_NAME']).strip().split('.')))
48 PORT = "443"49 PORT = "443"
@@ -54,7 +55,7 @@
5455
55 if answer.header['status'] == "NOERROR":56 if answer.header['status'] == "NOERROR":
56 logger = logging.getLogger('root')57 logger = logging.getLogger('root')
57 logger.info('Client %s is using TOR' % client)58 logger.info('Client %s is using TOR' % remote_addr)
58 return True59 return True
59 return False60 return False
6061
6162
=== modified file 'awstrial/trial/ec2_helper.py'
--- awstrial/trial/ec2_helper.py 2011-10-18 13:58:40 +0000
+++ awstrial/trial/ec2_helper.py 2011-10-20 23:51:23 +0000
@@ -21,6 +21,7 @@
2121
22from trial.models import Campaign, Instances22from trial.models import Campaign, Instances
23from django.contrib.auth.models import User23from django.contrib.auth.models import User
24from django.contrib.sites.models import Site
24from django.template.loader import render_to_string25from django.template.loader import render_to_string
2526
26from django.conf import settings27from django.conf import settings
@@ -62,8 +63,7 @@
6263
63 return connection64 return connection
6465
65def runit(campaign,lpid=None,regions=None,config=None, byobu=False,66def runit(campaign,lpid=None,regions=None,config=None, password=None):
66 password=None):
67 sec_key = util.rand_str(32)67 sec_key = util.rand_str(32)
68 if regions is None:68 if regions is None:
69 regions = [r for r in settings.REGIONS_TRY_ORDER69 regions = [r for r in settings.REGIONS_TRY_ORDER
@@ -72,7 +72,6 @@
72 if settings.REGION2AMI.has_key(r)]72 if settings.REGION2AMI.has_key(r)]
7373
74 cust = { }74 cust = { }
75 cust['byobu'] = False
76 cust['config'] = config75 cust['config'] = config
77 cust['password'] = password76 cust['password'] = password
7877
@@ -82,8 +81,9 @@
82 render_to_string("import-launchpad-ssh-keys",81 render_to_string("import-launchpad-ssh-keys",
83 { 'debug' : settings.DEBUG, 'launchpad_id' : lpid, 'password' : password } ),82 { 'debug' : settings.DEBUG, 'launchpad_id' : lpid, 'password' : password } ),
84 part_type=util.CI_SCRIPT, filename="10-launchpad-ssh-keys"))83 part_type=util.CI_SCRIPT, filename="10-launchpad-ssh-keys"))
85 84
86 callback_url = "%s/info_callback/%s" % (settings.BASE_URL, sec_key)85 site = Site.objects.get(pk=settings.SITE_ID)
86 callback_url = "%s/info_callback/%s" % (site.name, sec_key)
87 parts.append(87 parts.append(
88 util.partItem(88 util.partItem(
89 render_to_string("info-callback",89 render_to_string("info-callback",
@@ -113,12 +113,11 @@
113 { 'debug' : settings.DEBUG, 'user': 'ubuntu', 'password' : password }),113 { 'debug' : settings.DEBUG, 'user': 'ubuntu', 'password' : password }),
114 part_type=util.CI_SCRIPT, filename="55-password-enable"))114 part_type=util.CI_SCRIPT, filename="55-password-enable"))
115115
116 if str(byobu).lower() == "true":116 parts.append(
117 parts.append(117 util.partItem(
118 util.partItem(118 render_to_string("byobu-countdown", { 'debug' : settings.DEBUG, }),
119 render_to_string("byobu-enable", { 'debug' : settings.DEBUG, }),119 part_type=util.CI_BOOTHOOK, filename="byobu-countdown"))
120 part_type=util.CI_BOOTHOOK, filename="byobu-enable"))120 cust['byobu']=True
121 cust['byobu']=True
122121
123 instcfg = None122 instcfg = None
124 for c in settings.CONFIGS:123 for c in settings.CONFIGS:
125124
=== modified file 'awstrial/trial/tests.py'
--- awstrial/trial/tests.py 2011-10-20 20:41:18 +0000
+++ awstrial/trial/tests.py 2011-10-20 23:51:23 +0000
@@ -25,6 +25,7 @@
25from django.test import TestCase as DjangoTestCase25from django.test import TestCase as DjangoTestCase
26from django.conf import settings26from django.conf import settings
27from django.contrib.auth.models import User27from django.contrib.auth.models import User
28from django.contrib.sites.models import Site
28from mock import patch, Mock29from mock import patch, Mock
29from trial import ec2_helper30from trial import ec2_helper
30from trial.models import Campaign, Instances31from trial.models import Campaign, Instances
@@ -99,6 +100,7 @@
99 self.old_access_key = getattr(settings, 'AWS_ACCESS_KEY_ID', None)100 self.old_access_key = getattr(settings, 'AWS_ACCESS_KEY_ID', None)
100 self.old_secret_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)101 self.old_secret_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)
101 self.old_alternate_cloud = getattr(settings, 'ALTERNATE_CLOUD', None)102 self.old_alternate_cloud = getattr(settings, 'ALTERNATE_CLOUD', None)
103 self.old_site_id = getattr(settings, 'SITE_ID', None)
102 settings.AWS_ACCESS_KEY_ID = 'TestAccessKey'104 settings.AWS_ACCESS_KEY_ID = 'TestAccessKey'
103 settings.AWS_SECRET_ACCESS_KEY = 'TestSecretKey'105 settings.AWS_SECRET_ACCESS_KEY = 'TestSecretKey'
104 settings.ALTERNATE_CLOUD = None106 settings.ALTERNATE_CLOUD = None
@@ -107,6 +109,7 @@
107 settings.AWS_ACCESS_KEY_ID = self.old_access_key109 settings.AWS_ACCESS_KEY_ID = self.old_access_key
108 settings.AWS_SECRET_ACCESS_KEY = self.old_secret_key110 settings.AWS_SECRET_ACCESS_KEY = self.old_secret_key
109 settings.ALTERNATE_CLOUD = self.old_alternate_cloud111 settings.ALTERNATE_CLOUD = self.old_alternate_cloud
112 settings.SITE_ID = self.old_site_id
110113
111 def call_run_instance(self, campaign):114 def call_run_instance(self, campaign):
112 post_data = {115 post_data = {
@@ -117,6 +120,63 @@
117 return self.client.post('/%s/run/' % campaign.name, post_data)120 return self.client.post('/%s/run/' % campaign.name, post_data)
118121
119 @patch('boto.ec2.EC2Connection')122 @patch('boto.ec2.EC2Connection')
123 def test_uses_sites_framework(self, mock_connection):
124 """
125 Checks that the callback url is based off the Site.name for this
126 configuration
127 """
128
129 newsite = Site.objects.create(
130 domain='testing.awstrial.org',
131 name='http://testing.awstrial.org:8000',
132 )
133 settings.SITE_ID = newsite.id
134 self.call_count=0
135 class MockInstance(object):
136
137 def __init__(self, instance_id):
138 self.id = instance_id
139
140 class MockReservation(object):
141
142 def __init__(self, instance_ids):
143 self.instances = [MockInstance(i) for i in instance_ids]
144
145 campaign = Campaign.objects.create(
146 name='test-campaign',
147 verbose_name='Test Campaign',
148 max_instances=5,
149 active=True,
150 )
151
152 def mock_run_instances(conn, *args, **kwargs):
153 self.call_count += 1
154 self.assertTrue('user_data' in kwargs)
155
156 import StringIO, gzip, email
157 gzipped_mime_data = StringIO.StringIO()
158 gzipped_mime_data.write(kwargs['user_data'])
159 gzipped_mime_data.seek(0)
160 gzipped_mime_file = gzip.GzipFile(fileobj=gzipped_mime_data, mode='r')
161 mime_data = gzipped_mime_file.read()
162 mime_msg = email.message_from_string(mime_data)
163 self.assertTrue(mime_msg.is_multipart())
164
165 for mime_part in mime_msg.get_payload():
166 if mime_part.get_filename() == '99-info-callback':
167 self.assertTrue('http://testing.awstrial.org:8000/info_callback/' in mime_part.get_payload())
168
169 return MockReservation(['i-test-%s'%self.call_count])
170 mock_connection.return_value.run_instances.side_effect = mock_run_instances
171
172 user = User.objects.create_user('testuser', 'test@example.com', 'testpasswd')
173 self.client.login(username='testuser', password='testpasswd')
174
175 response = self.call_run_instance(campaign)
176 self.assertEquals(1, Instances.objects.all().count())
177 instance = Instances.objects.all()[0]
178
179 @patch('boto.ec2.EC2Connection')
120 def test_disallow_multiple_instances(self, mock_connection):180 def test_disallow_multiple_instances(self, mock_connection):
121 """181 """
122 Checks that a user can't create multiple isntances by making requests182 Checks that a user can't create multiple isntances by making requests
@@ -333,11 +393,16 @@
333 super(LogHandlerTestCase, self).setUp()393 super(LogHandlerTestCase, self).setUp()
334 self.memento_handler = self.MementoHandler()394 self.memento_handler = self.MementoHandler()
335 self.root_logger = logging.getLogger()395 self.root_logger = logging.getLogger()
396 self.root_logger.setLevel(logging.INFO)
336 self.root_logger.addHandler(self.memento_handler)397 self.root_logger.addHandler(self.memento_handler)
398 self.old_block_tor = settings.USER_BLOCK_TOR_GATEWAY
399 self.old_block_email = settings.USER_BLOCK_EMAIL_BLACKLIST
337400
338 def tearDown(self):401 def tearDown(self):
339 """Remove the memento handler from the root logger."""402 """Remove the memento handler from the root logger."""
340 self.root_logger.removeHandler(self.memento_handler)403 self.root_logger.removeHandler(self.memento_handler)
404 settings.USER_BLOCK_TOR_GATEWAY = self.old_block_tor
405 settings.USER_BLOCK_EMAIL_BLACKLIST = self.old_block_email
341 super(LogHandlerTestCase, self).tearDown()406 super(LogHandlerTestCase, self).tearDown()
342407
343 def assertLogLevelContains(self, level, message, with_exc_info=False):408 def assertLogLevelContains(self, level, message, with_exc_info=False):
@@ -346,19 +411,25 @@
346 self.assertTrue(411 self.assertTrue(
347 self.memento_handler.check(level, message, with_exc_info))412 self.memento_handler.check(level, message, with_exc_info))
348413
349 def test_client_using_tor(self):414 @patch('DNS.DnsRequest')
415 def test_client_using_tor(self, mock_dns_request):
350 # verify that a client that is a TOR exit node is blocked416 # verify that a client that is a TOR exit node is blocked
351 tor_exit = socket.gethostbyname('ip-port.exitlist.torproject.org')417 settings.USER_BLOCK_TOR_GATEWAY = True
352 request = MockRequest()418 request = MockRequest()
353 request.META['SERVER_NAME'] = '127.0.0.1'419 request.META['SERVER_NAME'] = '127.0.0.1'
354 request.META['REMOTE_ADDR'] = tor_exit420 request.META['REMOTE_ADDR'] = '127.0.0.2'
421 mock_dns_request.return_value.req.side_effect = type('answer', (), {'header': {'status': 'NOERROR'}})
355 self.assertTrue(client_using_tor(request))422 self.assertTrue(client_using_tor(request))
423 self.assertLogLevelContains('INFO', 'Client 127.0.0.2 is using TOR')
356 424
357 def test_client_not_using_tor(self):425 @patch('DNS.DnsRequest')
426 def test_client_not_using_tor(self, mock_dns_request):
358 # verify that a client that is not a TOR exit node is not blocked427 # verify that a client that is not a TOR exit node is not blocked
359 me = socket.gethostname()428 settings.USER_BLOCK_TOR_GATEWAY = True
360 request = MockRequest()429 request = MockRequest()
361 request.META['SERVER_NAME'] = '127.0.0.1'430 request.META['SERVER_NAME'] = '127.0.0.1'
362 request.META['REMOTE_ADDR'] = me431 request.META['REMOTE_ADDR'] = '127.0.0.2'
432 mock_dns_request.return_value.req.side_effect = type('answer', (), {'header': {'status': 'ERROR'}})
363 self.assertFalse(client_using_tor(request))433 self.assertFalse(client_using_tor(request))
434 self.assertFalse(self.memento_handler.check('INFO', 'Client 127.0.0.2 is using TOR'))
364435
365436
=== modified file 'awstrial/trial/views.py'
--- awstrial/trial/views.py 2011-10-18 20:11:39 +0000
+++ awstrial/trial/views.py 2011-10-20 23:51:23 +0000
@@ -86,14 +86,13 @@
86 else:86 else:
87 regions = settings.REGIONS_TRY_ORDER87 regions = settings.REGIONS_TRY_ORDER
88 config = request.POST.get('config', '')88 config = request.POST.get('config', '')
89 byobu = request.POST.get('byobu','')
90 set_password = request.POST.get('set_password',None)89 set_password = request.POST.get('set_password',None)
9190
92 password=None91 password=None
93 if set_password:92 if set_password:
94 password=util.rand_user_password()93 password=util.rand_user_password()
9594
96 ec2_helper.runit(campaign,lpid=request.user, regions=regions, config=config, byobu=byobu, password=password)95 ec2_helper.runit(campaign,lpid=request.user, regions=regions, config=config, password=password)
97 #send_mail(subject, message, from_email, ['davewalker@ubuntu.com'])96 #send_mail(subject, message, from_email, ['davewalker@ubuntu.com'])
98 #except BadHeaderError: #Example of basic error handling97 #except BadHeaderError: #Example of basic error handling
99 # return HttpResponse('Invalid header found.')98 # return HttpResponse('Invalid header found.')

Subscribers

People subscribed via source and target branches

to all changes: