Author: Brad Crittenden <bac@canonical.com>
Description: Make control-bucket optional
Origin: upstream, http://bazaar.launchpad.net/~juju-gui/juju-quickstart/trunk/revision/65
Bug: https://launchpad.net/bugs/1309678
Bug-Ubuntu: https://launchpad.net/bugs/1309678
Last-Update: 2014-06-27

------------------------------------------------------------
revno: 65 [merge]
committer: Brad Crittenden <bac@canonical.com>
branch nick: juju-quickstart
timestamp: Tue 2014-04-22 09:16:21 -0400
message:
  Make control-bucket optional.
  
  The existing function get_admin_secret is made generic and the name is changed
  to get_value_from_jenv.  It now takes a keyname to be fetched from the
  generated file.
  
  For both ec2 and openstack the control-bucket field has been made optional
  with respect to the environments.yaml file.
  
  QA:
  
  1) Create an ec2 environment with no control-bucket.
  2) Bootstrap that environment.  Ensure a control-bucket is in the .jenv file.
  3) Run quickstart and see that it uses the existing environment and does not
  raise an error.
  
  R=frankban
  CC=
  https://codereview.appspot.com/90060043

=== modified file 'quickstart/app.py'
--- old/quickstart/app.py	2014-04-04 17:46:47 +0000
+++ new/quickstart/app.py	2014-04-21 21:05:13 +0000
@@ -238,25 +238,27 @@
     raise ProgramExit('the state server is not ready:\n{}'.format(details))
 
 
-def get_admin_secret(env_name, juju_home):
-    """Read the admin-secret from the generated environment file.
-
-    At bootstrap, juju (v1.16 and later) writes the admin-secret to a
-    generated file located in JUJU_HOME.  Return the value.
+def get_value_from_jenv(env_name, juju_home, key):
+
+    """Read the key from the generated environment file.
+
+    At bootstrap, juju (v1.16 and later) writes a generated file
+    located in JUJU_HOME.  Return the value for the key.
+
     Raise a ValueError if:
         - the environment file is not found;
         - the environment file contents are not parsable by YAML;
         - the YAML contents are not properly structured;
-        - the admin-secret is not found.
+        - the key is not found.
     """
     filename = '{}.jenv'.format(env_name)
     juju_env_file = os.path.expanduser(
         os.path.join(juju_home, 'environments', filename))
     jenv_db = envs.load_generated(juju_env_file)
     try:
-        return jenv_db['admin-secret']
+        return jenv_db[key]
     except KeyError:
-        msg = 'admin-secret not found in {}'.format(juju_env_file)
+        msg = '{} not found in {}'.format(key, juju_env_file)
         raise ValueError(msg.encode('utf-8'))
 
 

=== modified file 'quickstart/manage.py'
--- old/quickstart/manage.py	2014-04-07 15:52:55 +0000
+++ new/quickstart/manage.py	2014-04-22 12:20:10 +0000
@@ -463,8 +463,8 @@
 
     # Retrieve the admin-secret for the current environment.
     try:
-        admin_secret = app.get_admin_secret(
-            options.env_name, settings.JUJU_HOME)
+        admin_secret = app.get_value_from_jenv(
+            options.env_name, settings.JUJU_HOME, 'admin-secret')
     except ValueError as err:
         admin_secret = options.admin_secret
         if admin_secret is None:

=== modified file 'quickstart/models/envs.py'
--- old/quickstart/models/envs.py	2014-04-10 09:22:37 +0000
+++ new/quickstart/models/envs.py	2014-04-21 21:02:09 +0000
@@ -477,7 +477,7 @@
                 help='The secret key to use to authenticate to AWS. '
                      'See the access key help above.'),
             fields.AutoGeneratedStringField(
-                'control-bucket', label='control bucket', required=True,
+                'control-bucket', label='control bucket', required=False,
                 help='the globally unique S3 bucket name'),
             fields.ChoiceField(
                 'region', choices=ec2_regions, default='us-east-1',
@@ -508,7 +508,7 @@
                      'Some installations assign public IP addresses by '
                      'default without requiring a floating IP address.'),
             fields.AutoGeneratedStringField(
-                'control-bucket', label='control bucket', required=True,
+                'control-bucket', label='control bucket', required=False,
                 help='the globally unique swift bucket name'),
             fields.SuggestionsStringField(
                 'auth-url', label='authentication URL', required=True,

=== modified file 'quickstart/tests/models/test_envs.py'
--- old/quickstart/tests/models/test_envs.py	2014-04-03 08:24:13 +0000
+++ new/quickstart/tests/models/test_envs.py	2014-04-21 21:02:09 +0000
@@ -745,7 +745,7 @@
             'secret-key', 'control-bucket', 'region', 'is-default']
         expected_required = [
             'type', 'name', 'access-key', 'secret-key',
-            'control-bucket', 'is-default']
+            'is-default']
         self.assert_fields(expected, env_metadata)
         self.assert_required_fields(expected_required, env_metadata)
 
@@ -760,8 +760,7 @@
             'secret-key', 'is-default']
         expected_required = [
             'type', 'name', 'use-floating-ip',
-            'control-bucket', 'auth-url', 'tenant-name', 'region',
-            'is-default']
+            'auth-url', 'tenant-name', 'region', 'is-default']
         self.assert_fields(expected, env_metadata)
         self.assert_required_fields(expected_required, env_metadata)
 

=== modified file 'quickstart/tests/test_app.py'
--- old/quickstart/tests/test_app.py	2014-04-04 15:49:16 +0000
+++ new/quickstart/tests/test_app.py	2014-04-21 21:02:09 +0000
@@ -572,23 +572,25 @@
         ] + self.make_status_calls(2))
 
 
-class TestGetAdminSecret(unittest.TestCase):
+class TestGetValueFromJenv(unittest.TestCase):
 
-    def test_no_admin_secret(self):
+    def test_no_key(self):
         with mock.patch('quickstart.manage.envs.load_generated',
                         lambda x: {}):
             with self.assertRaises(ValueError) as exc:
-                app.get_admin_secret('local', '/home/bac/.juju')
+                app.get_value_from_jenv(
+                    'local', '/home/bac/.juju', 'my-key')
         expected = (
-            u'admin-secret not found in '
+            u'my-key not found in '
             '/home/bac/.juju/environments/local.jenv')
         self.assertIn(expected, bytes(exc.exception))
 
     def test_success(self):
         expected = 'superchunk'
         with mock.patch('quickstart.manage.envs.load_generated',
-                        lambda x: {'admin-secret': expected}):
-            secret = app.get_admin_secret('local', '~bac/.juju')
+                        lambda x: {'my-key': expected}):
+            secret = app.get_value_from_jenv(
+                'local', '~bac/.juju', 'my-key')
         self.assertEqual(expected, secret)
 
 

=== modified file 'quickstart/tests/test_manage.py'
--- old/quickstart/tests/test_manage.py	2014-04-07 10:29:29 +0000
+++ new/quickstart/tests/test_manage.py	2014-04-22 12:20:10 +0000
@@ -706,21 +706,21 @@
         return mock.Mock(**options)
 
     @staticmethod
-    def mock_get_admin_secret_success(name, home):
-        return 'jenv secret'
+    def mock_get_value_from_jenv_success(name, home, key):
+        return 'from jenv'
 
     @staticmethod
-    def mock_get_admin_secret_error(name, home):
+    def mock_get_value_from_jenv_error(name, home, key):
         fn = '{}.jenv'.format(name)
         path = os.path.join(home, 'environments', fn)
-        msg = 'admin-secret not found in {}'.format(path)
+        msg = '{} not found in {}'.format(key, path)
         raise ValueError(msg.encode('utf-8'))
 
     def test_no_bundle(self, mock_app, mock_open):
         # The application runs correctly if no bundle is provided.
         mock_app.ensure_dependencies.return_value = (1, 18, 0)
         mock_app.bootstrap.return_value = (True, 'precise')
-        mock_app.get_admin_secret = self.mock_get_admin_secret_error
+        mock_app.get_value_from_jenv = self.mock_get_value_from_jenv_error
         mock_app.watch.return_value = '1.2.3.4'
         mock_app.create_auth_token.return_value = 'AUTHTOKEN'
         options = self.make_options()
@@ -815,18 +815,18 @@
     def test_admin_secret_fetched(self, mock_app, mock_open):
         # If an admin secret is fetched from jenv it is used, even if one is
         # found in environments.yaml, as set in options.admin_secret.
-        mock_app.get_admin_secret = self.mock_get_admin_secret_success
+        mock_app.get_value_from_jenv = self.mock_get_value_from_jenv_success
         mock_app.bootstrap.return_value = (True, 'precise')
         options = self.make_options(admin_secret='secret in environments.yaml')
         manage.run(options)
         mock_app.connect.assert_has_calls([
-            mock.call(mock_app.get_api_url(), 'jenv secret'),
+            mock.call(mock_app.get_api_url(), 'from jenv'),
         ])
 
     def test_admin_secret_from_environments_yaml(self, mock_app, mock_open):
         # If an admin secret is not fetched from jenv, then the one from
         # environments.yaml is used, as found in options.admin_secret.
-        mock_app.get_admin_secret = self.mock_get_admin_secret_error
+        mock_app.get_value_from_jenv = self.mock_get_value_from_jenv_error
         mock_app.bootstrap.return_value = (True, 'precise')
         options = self.make_options(admin_secret='secret in environments.yaml')
         manage.run(options)
@@ -837,7 +837,7 @@
     def test_no_admin_secret_found(self, mock_app, mock_open):
         # If admin-secret cannot be found anywhere a ProgramExit is called.
         mock_app.ProgramExit = app.ProgramExit
-        mock_app.get_admin_secret = self.mock_get_admin_secret_error
+        mock_app.get_value_from_jenv = self.mock_get_value_from_jenv_error
         mock_app.bootstrap.return_value = (True, 'precise')
         options = self.make_options(
             admin_secret=None,

