Merge lp:~tvansteenburgh/juju-deployer/abspath-charms into lp:juju-deployer

Proposed by Tim Van Steenburgh
Status: Merged
Merged at revision: 150
Proposed branch: lp:~tvansteenburgh/juju-deployer/abspath-charms
Merge into: lp:juju-deployer
Diff against target: 156 lines (+66/-5)
4 files modified
deployer/action/importer.py (+4/-3)
deployer/charm.py (+32/-2)
deployer/env/base.py (+6/-0)
deployer/tests/test_charm.py (+24/-0)
To merge this branch: bzr merge lp:~tvansteenburgh/juju-deployer/abspath-charms
Reviewer Review Type Date Requested Status
Marco Ceppi (community) Approve
juju-deployers Pending
Review via email: mp+266329@code.launchpad.net

Description of the change

Allow charms to be specified using an absolute local path.

For example:

    services:
        mycharm:
            charm: /tmp/trusty/mycharm

Primary rationale for this is to allow rapid iteration on a charm's amulet
tests, without needing to commit the changes, or even have them under
revision control. For the charm under test, amulet will give deployer an
absolute path, ensuring that the version of the charm that is deployed and
tested is whatever is on disk at the time.

To post a comment you must log in.
Revision history for this message
Marco Ceppi (marcoceppi) wrote :

+1 this will simplify a lot of tools and workloads for people!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'deployer/action/importer.py'
2--- deployer/action/importer.py 2015-05-28 13:04:30 +0000
3+++ deployer/action/importer.py 2015-07-29 21:29:11 +0000
4@@ -3,7 +3,6 @@
5
6 from .base import BaseAction
7 from ..env import watchers
8-from ..errors import UnitErrors
9 from ..utils import ErrorExit
10
11
12@@ -180,7 +179,9 @@
13
14 charm = self.deployment.get_charm_for(svc.name)
15 self.log.info(
16- " Deploying service %s using %s", svc.name, charm.charm_url)
17+ " Deploying service %s using %s", svc.name,
18+ charm.charm_url if not charm.is_absolute() else charm.path
19+ )
20
21 if svc.unit_placement:
22 # We sorted all the non placed services first, so we only
23@@ -217,7 +218,7 @@
24 self.env.deploy(
25 svc.name,
26 charm.charm_url,
27- self.deployment.repo_path,
28+ charm.repo_path or self.deployment.repo_path,
29 svc.config,
30 svc.constraints,
31 num_units,
32
33=== modified file 'deployer/charm.py'
34--- deployer/charm.py 2015-07-21 07:51:43 +0000
35+++ deployer/charm.py 2015-07-29 21:29:11 +0000
36@@ -70,6 +70,9 @@
37 else:
38 series = deploy_series
39 charm_path = path_join(repo_path, series, name)
40+ elif os.path.isabs(name):
41+ # charm points to an absolute local path
42+ charm_path = name.rstrip(os.path.sep)
43 elif 'series' in data:
44 series = data['series']
45 charm_path = path_join(repo_path, series, name)
46@@ -83,7 +86,7 @@
47 cls.log.error(
48 "Service: %s has both charm url: %s and branch: %s specified",
49 name, store_url, branch)
50- if not store_url and not branch:
51+ if not store_url and not branch and not os.path.isabs(name):
52 cls.log.error(
53 "Service: %s has neither charm url or branch specified",
54 name)
55@@ -92,6 +95,31 @@
56
57 return cls(name, charm_path, branch, rev, build, store_url)
58
59+ def is_absolute(self):
60+ """Charm config points to an absolute path on disk.
61+
62+ """
63+ return os.path.isabs(self.name)
64+
65+ @property
66+ def repo_path(self):
67+ """The Juju repository path in which this charm resides.
68+
69+ For most charms this returns None, leaving the repo path to be
70+ determined by the Deployment that deploys the charm.
71+
72+ For charms at an absolute path, however, the repo path is by
73+ definition the directory two levels up from the charm. (And the
74+ series directory is one level up.) This allows us to deploy
75+ charms from anywhere on the filesystem without first gathering them
76+ under one repository path.
77+
78+ """
79+ if self.is_absolute():
80+ d = os.path.dirname
81+ return d(d(self.path))
82+ return None
83+
84 def is_local(self):
85 if self._charm_url:
86 if self._charm_url.startswith('cs:'):
87@@ -124,6 +152,8 @@
88 if self._charm_url:
89 self._fetch_store_charm()
90 return
91+ elif self.is_absolute():
92+ return
93 elif not self.branch:
94 self.log.warning("Invalid charm specification %s", self.name)
95 return
96@@ -141,7 +171,7 @@
97
98 @property
99 def series_path(self):
100- if not self.is_local():
101+ if self.is_absolute() or not self.is_local():
102 return None
103 return os.path.dirname(self.path)
104
105
106=== modified file 'deployer/env/base.py'
107--- deployer/env/base.py 2015-06-18 08:34:12 +0000
108+++ deployer/env/base.py 2015-07-29 21:29:11 +0000
109@@ -86,6 +86,12 @@
110 fh.flush()
111 params.extend(["--config", fh.name])
112 if constraints:
113+ if isinstance(constraints, list):
114+ constraints = ' '.join(constraints)
115+ if isinstance(constraints, dict):
116+ constraints = ' '.join([
117+ '{}={}'.format(k, v) for k, v in constraints.items()
118+ ])
119 params.extend(['--constraints', constraints])
120 if num_units not in (1, None):
121 params.extend(["--num-units", str(num_units)])
122
123=== modified file 'deployer/tests/test_charm.py'
124--- deployer/tests/test_charm.py 2014-09-29 14:36:34 +0000
125+++ deployer/tests/test_charm.py 2015-07-29 21:29:11 +0000
126@@ -9,6 +9,30 @@
127 from .base import Base
128
129
130+class StoreCharmTest(Base):
131+ def setUp(self):
132+ self.charm = Charm(
133+ 'cs:trusty/ubuntu', None, None, None, None)
134+
135+ def test_is_absolute(self):
136+ self.assertFalse(self.charm.is_absolute())
137+
138+ def test_repo_path(self):
139+ self.assertIsNone(self.charm.repo_path)
140+
141+
142+class AbsolutePathCharmTest(Base):
143+ def setUp(self):
144+ self.charm = Charm(
145+ '/tmp/trusty/ubuntu', '/tmp/trusty/ubuntu', None, None, None)
146+
147+ def test_is_absolute(self):
148+ self.assertTrue(self.charm.is_absolute())
149+
150+ def test_repo_path(self):
151+ self.assertEqual('/tmp', self.charm.repo_path)
152+
153+
154 class Bzr(BaseBzr):
155
156 def __init__(self, path):

Subscribers

People subscribed via source and target branches