diff --git a/.travis/install.sh b/.travis/install.sh index f7609d7..6d3a8c7 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -12,7 +12,6 @@ EOR if [[ $JUJU_VERSION == 2 ]]; then sudo add-apt-repository -y ppa:juju/stable - sudo add-apt-repository -y ppa:ubuntu-lxc/lxd-stable JUJU_PKGS="juju lxd" else sudo add-apt-repository -y ppa:juju/1.25 @@ -20,7 +19,7 @@ else fi sudo apt-get update -sudo apt-get install -y bzr $JUJU_PKGS +sudo apt-get install -t trusty-backports -y bzr $JUJU_PKGS if [[ $JUJU_VERSION == 2 ]]; then echo User: $USER diff --git a/amulet/deployer.py b/amulet/deployer.py index 5699bde..952c7a5 100644 --- a/amulet/deployer.py +++ b/amulet/deployer.py @@ -155,7 +155,8 @@ def load(self, deploy_cfg, deployment_name=None): constraints=constraints, placement=service_config.get('to', None), series=self.series, - storage=service_config.get('storage') + storage=service_config.get('storage'), + resources=service_config.get('resources') ) if service_config.get('options'): @@ -171,7 +172,8 @@ def add(self, service_name, branch=None, placement=None, series=None, - storage=None): + storage=None, + resources=None): """Add a new service to the deployment schema. :param service_name: Name of the service to deploy. @@ -189,6 +191,8 @@ def add(self, service_name, :param series: Series of charm to deploy, e.g. precise, trusty, xenial :param storage: Storage configuration as a dictionary with key the label and value being the pool,size,count string used by Juju. + :param resources: Resources configuration as a dictionary with key the + resource name and value the local path to the file Example:: @@ -198,6 +202,8 @@ def add(self, service_name, d.add('second-wp', charm='wordpress') d.add('personal-wp', charm='~marcoceppi/wordpress', units=2) d.add('postgresql', storage={'pgdata', 'rootfs,50M'}) + d.add('etcd', resources={'snapshot': './snapshot.tgz', + 'etcd': 'etcd.snap'}) """ if self.deployed: @@ -214,6 +220,11 @@ def add(self, service_name, raise ValueError('Storage must be specified as a dict') service['storage'] = storage + if resources is not None: + if not isinstance(resources, dict): + raise ValueError('Resources must be specified as a dict') + service['resources'] = resources + charm = self.charm_cache.fetch( service_name, charm, branch=branch, series=service['series']) @@ -546,6 +557,38 @@ def configure(self, service, options): else: self.services[service]['options'].update(options) + def attach(self, service, resources): + """Attaches resources to a service (deployed or not). + + :param service: Name of the service to hold the attachments + :param resources: Dictionary of resources to attach + + Example: + + import amulet + d = amulet.Deployment() + d.add('etcd') + d.attach('etc', {'snapshot': 'snapshot.tgz'}) + + """ + if JUJU_VERSION.major == 1: + raise NotImplementedError( + 'Resources feature not implemented in this juju version') + + if self.deployed: + args = ['attach', service] + for k, v in resources.items(): + args.append("%s=%s" % (k, v)) + return juju(args) + + if service not in self.services: + raise ValueError('Service has not yet been described') + + if 'resources' not in self.services[service]: + self.services[service]['resources'] = resources + else: + self.services[service]['resources'].update(resources) + def expose(self, service): """Expose a service. diff --git a/tests/test_deployer.py b/tests/test_deployer.py index 5d5f7ce..e6468eb 100644 --- a/tests/test_deployer.py +++ b/tests/test_deployer.py @@ -65,6 +65,7 @@ def test_load(self): placement=None, series='raring', storage={"wp-data": "rootfs,100M"}, + resources=None, units=1, branch='lp:~charmers/charms/precise/wordpress/trunk', constraints=None, @@ -73,6 +74,7 @@ def test_load(self): placement=None, series='raring', storage=None, + resources=None, units=1, branch='lp:~charmers/charms/precise/mysql/trunk', constraints={'mem': '2G', 'cpu-cores': '2'},