Merge lp:~frankban/charms/precise/juju-gui/api-address into lp:~juju-gui/charms/precise/juju-gui/trunk

Proposed by Francesco Banconi
Status: Merged
Merged at revision: 61
Proposed branch: lp:~frankban/charms/precise/juju-gui/api-address
Merge into: lp:~juju-gui/charms/precise/juju-gui/trunk
Diff against target: 152 lines (+81/-27)
3 files modified
hooks/utils.py (+18/-7)
revision (+1/-1)
tests/test_utils.py (+62/-19)
To merge this branch: bzr merge lp:~frankban/charms/precise/juju-gui/api-address
Reviewer Review Type Date Requested Status
charmers Pending
Review via email: mp+166808@code.launchpad.net

Description of the change

Take the juju API address from the environment

The charm now tries to retrieve the juju API
address from the hook context before parsing
the machiner agent file.

This way we take advantage of a change in juju-core
currently in review, which introduces the corresponding
functionality.

https://codereview.appspot.com/9810044/

To post a comment you must log in.
Revision history for this message
Francesco Banconi (frankban) wrote :

Reviewers: mp+166808_code.launchpad.net,

Message:
Please take a look.

Description:
Take the juju API address from the environment

The charm now tries to retrieve the juju API
address from the hook context before parsing
the machiner agent file.

This way we take advantage of a change in juju-core
currently in review, which introduces the corresponding
functionality.

https://code.launchpad.net/~frankban/charms/precise/juju-gui/api-address/+merge/166808

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/9810044/

Affected files:
   A [revision details]
   M hooks/utils.py
   M revision
   M tests/test_utils.py

Revision history for this message
Nicola Larosa (teknico) wrote :

LGTM, nice code and tests. A few trivials.

https://codereview.appspot.com/9810044/diff/1/hooks/utils.py
File hooks/utils.py (right):

https://codereview.appspot.com/9810044/diff/1/hooks/utils.py#newcode135
hooks/utils.py:135: base_dir = os.path.abspath(base_dir)
Sorry, can't resist: :-)

     segs = (CURRENT_DIR, '..', '..') if unit_dir is None else (unit_dir,
'..')
     base_dir = os.path.abspath(os.path.join(*segs))

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py
File tests/test_utils.py (right):

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py#newcode97
tests/test_utils.py:97: If addresses are provided, also create a
machiner directory and an
What's a "machiner"?

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py#newcode133
tests/test_utils.py:133: # The API address is correctly retrieved from
the machiner agent file.
"machiner" again.

https://codereview.appspot.com/9810044/

Revision history for this message
Brad Crittenden (bac) wrote :

LGTM, thanks

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py
File tests/test_utils.py (right):

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py#newcode98
tests/test_utils.py:98: agent file containing the addresses.
So I looked at the juju-core code and they strongly have the concept of
a 'machiner', an agent that oversees the lifecycle of a machine. So as
odd as it looks in this context I guess we should go with it.

https://codereview.appspot.com/9810044/

Revision history for this message
Francesco Banconi (frankban) wrote :

*** Submitted:

Take the juju API address from the environment

The charm now tries to retrieve the juju API
address from the hook context before parsing
the machiner agent file.

This way we take advantage of a change in juju-core
currently in review, which introduces the corresponding
functionality.

R=
CC=
https://codereview.appspot.com/9810044

https://codereview.appspot.com/9810044/diff/1/hooks/utils.py
File hooks/utils.py (right):

https://codereview.appspot.com/9810044/diff/1/hooks/utils.py#newcode135
hooks/utils.py:135: base_dir = os.path.abspath(base_dir)
On 2013/05/31 15:22:04, teknico wrote:
> Sorry, can't resist: :-)

> segs = (CURRENT_DIR, '..', '..') if unit_dir is None else
(unit_dir, '..')
> base_dir = os.path.abspath(os.path.join(*segs))

I agree this avoids some code duplication and it's cool, but I still
consider my version slightly more readable.

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py
File tests/test_utils.py (right):

https://codereview.appspot.com/9810044/diff/1/tests/test_utils.py#newcode98
tests/test_utils.py:98: agent file containing the addresses.
On 2013/06/03 13:08:36, bac wrote:
> So I looked at the juju-core code and they strongly have the concept
of a
> 'machiner', an agent that oversees the lifecycle of a machine. So as
odd as it
> looks in this context I guess we should go with it.

Ok.

https://codereview.appspot.com/9810044/

Revision history for this message
Francesco Banconi (frankban) wrote :

Thanks fro the reviews Nicola and Brad!

https://codereview.appspot.com/9810044/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/utils.py'
2--- hooks/utils.py 2013-05-17 09:07:28 +0000
3+++ hooks/utils.py 2013-05-31 14:29:31 +0000
4@@ -115,13 +115,24 @@
5 cmd_log(apt_get_install(*DEB_BUILD_DEPENDENCIES))
6
7
8-def get_api_address(unit_dir):
9- """Return the Juju API address stored in the uniter agent.conf file."""
10+def get_api_address(unit_dir=None):
11+ """Return the Juju API address.
12+
13+ If not present in the hook context as an environment variable, try to
14+ retrieve the address parsing the machiner agent.conf file.
15+ """
16+ api_addresses = os.getenv("JUJU_API_ADDRESSES")
17+ if api_addresses is not None:
18+ return api_addresses.split()[0]
19+ # The JUJU_API_ADDRESSES environment variable is not included in the hooks
20+ # context in older releases of juju-core. Retrieve it from the machiner
21+ # agent file instead.
22 import yaml # python-yaml is only installed if juju-core is used.
23- # XXX 2013-03-27 frankban bug=1161443:
24- # currently the uniter agent.conf file does not include the API
25- # address. For now retrieve it from the machine agent file.
26- base_dir = os.path.abspath(os.path.join(unit_dir, '..'))
27+ if unit_dir is None:
28+ base_dir = os.path.join(CURRENT_DIR, '..', '..')
29+ else:
30+ base_dir = os.path.join(unit_dir, '..')
31+ base_dir = os.path.abspath(base_dir)
32 for dirname in os.listdir(base_dir):
33 if dirname.startswith('machine-'):
34 agent_conf = os.path.join(base_dir, dirname, 'agent.conf')
35@@ -390,7 +401,7 @@
36 api_address = '127.0.0.1:{0}'.format(API_PORT)
37 else:
38 # Retrieve the juju-core API server address.
39- api_address = get_api_address(os.path.join(CURRENT_DIR, '..'))
40+ api_address = get_api_address()
41 context = {
42 'api_address': api_address,
43 'api_pem': JUJU_PEM,
44
45=== modified file 'revision'
46--- revision 2013-05-23 13:34:03 +0000
47+++ revision 2013-05-31 14:29:31 +0000
48@@ -1,1 +1,1 @@
49-47
50+48
51
52=== modified file 'tests/test_utils.py'
53--- tests/test_utils.py 2013-05-11 00:18:47 +0000
54+++ tests/test_utils.py 2013-05-31 14:29:31 +0000
55@@ -9,6 +9,7 @@
56 import unittest
57
58 import charmhelpers
59+from shelltoolbox import environ
60 import tempita
61 import yaml
62
63@@ -86,28 +87,70 @@
64
65 class TestGetApiAddress(unittest.TestCase):
66
67- def setUp(self):
68- self.base_dir = tempfile.mkdtemp()
69- self.addCleanup(shutil.rmtree, self.base_dir)
70- self.unit_dir = tempfile.mkdtemp(dir=self.base_dir)
71- self.machine_dir = os.path.join(self.base_dir, 'machine-1')
72-
73- def test_retrieving_address(self):
74- # The API address is correctly returned.
75- address = 'example.com:17070'
76- os.mkdir(self.machine_dir)
77- with open(os.path.join(self.machine_dir, 'agent.conf'), 'w') as conf:
78- yaml.dump({'apiinfo': {'addrs': [address]}}, conf)
79- self.assertEqual(address, get_api_address(self.unit_dir))
80-
81- def test_missing_file(self):
82+ env_address = 'env.example.com:17070'
83+ agent_address = 'agent.example.com:17070'
84+
85+ @contextmanager
86+ def agent_file(self, addresses=None):
87+ """Set up a directory structure similar to the one created by juju.
88+
89+ If addresses are provided, also create a machiner directory and an
90+ agent file containing the addresses.
91+ Remove the directory structure when exiting from the context manager.
92+ """
93+ base_dir = tempfile.mkdtemp()
94+ unit_dir = tempfile.mkdtemp(dir=base_dir)
95+ machine_dir = os.path.join(base_dir, 'machine-1')
96+ if addresses is not None:
97+ os.mkdir(machine_dir)
98+ with open(os.path.join(machine_dir, 'agent.conf'), 'w') as conf:
99+ yaml.dump({'apiinfo': {'addrs': addresses}}, conf)
100+ try:
101+ yield unit_dir, machine_dir
102+ finally:
103+ shutil.rmtree(base_dir)
104+
105+ def test_retrieving_address_from_env(self):
106+ # The API address is correctly retrieved from the environment.
107+ with environ(JUJU_API_ADDRESSES=self.env_address):
108+ self.assertEqual(self.env_address, get_api_address())
109+
110+ def test_multiple_addresses_in_env(self):
111+ # If multiple API addresses are listed in the environment variable,
112+ # the first one is returned.
113+ addresses = '{} foo.example.com:42'.format(self.env_address)
114+ with environ(JUJU_API_ADDRESSES=addresses):
115+ self.assertEqual(self.env_address, get_api_address())
116+
117+ def test_both_env_and_agent_file(self):
118+ # If the API address is included in both the environment and the
119+ # agent.conf file, the environment variable takes precedence.
120+ with environ(JUJU_API_ADDRESSES=self.env_address):
121+ with self.agent_file([self.agent_address]) as (unit_dir, _):
122+ self.assertEqual(self.env_address, get_api_address(unit_dir))
123+
124+ def test_retrieving_address_from_agent_file(self):
125+ # The API address is correctly retrieved from the machiner agent file.
126+ with self.agent_file([self.agent_address]) as (unit_dir, _):
127+ self.assertEqual(self.agent_address, get_api_address(unit_dir))
128+
129+ def test_multiple_addresses_in_agent_file(self):
130+ # If multiple API addresses are listed in the agent file, the first
131+ # one is returned.
132+ addresses = [self.agent_address, 'foo.example.com:42']
133+ with self.agent_file(addresses) as (unit_dir, _):
134+ self.assertEqual(self.agent_address, get_api_address(unit_dir))
135+
136+ def test_missing_env_and_agent_file(self):
137 # An IOError is raised if the agent configuration file is not found.
138- os.mkdir(self.machine_dir)
139- self.assertRaises(IOError, get_api_address, self.unit_dir)
140+ with self.agent_file() as (unit_dir, machine_dir):
141+ os.mkdir(machine_dir)
142+ self.assertRaises(IOError, get_api_address, unit_dir)
143
144- def test_missing_directory(self):
145+ def test_missing_env_and_agent_directory(self):
146 # An IOError is raised if the machine directory is not found.
147- self.assertRaises(IOError, get_api_address, self.unit_dir)
148+ with self.agent_file() as (unit_dir, _):
149+ self.assertRaises(IOError, get_api_address, unit_dir)
150
151
152 class TestLegacyJuju(unittest.TestCase):

Subscribers

People subscribed via source and target branches