X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=blobdiff_plain;f=modules%2Flibjuju%2Fjuju%2Fapplication.py;h=84afebee4eff4faab86f82caf5968b4cf5678a84;hp=8719a629d2153b63374a3959b70f29c89d825793;hb=1afb30a22cc175cf67572b7195609be6a484258c;hpb=68858c1915122c2dbc8999a5cd3229694abf5f3a diff --git a/modules/libjuju/juju/application.py b/modules/libjuju/juju/application.py index 8719a62..84afebe 100644 --- a/modules/libjuju/juju/application.py +++ b/modules/libjuju/juju/application.py @@ -1,3 +1,17 @@ +# Copyright 2016 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import logging @@ -37,6 +51,24 @@ class Application(model.ModelEntity): if unit.application == self.name ] + @property + def relations(self): + return [rel for rel in self.model.relations if rel.matches(self.name)] + + def related_applications(self, endpoint_name=None): + apps = {} + for rel in self.relations: + if rel.is_peer: + local_ep, remote_ep = rel.endpoints[0] + else: + def is_us(ep): + return ep.application.name == self.name + local_ep, remote_ep = sorted(rel.endpoints, key=is_us) + if endpoint_name is not None and endpoint_name != local_ep.name: + continue + apps[remote_ep.application.name] = remote_ep.application + return apps + @property def status(self): """Get the application status, as set by the charm's leader. @@ -196,13 +228,24 @@ class Application(model.ModelEntity): result = (await app_facade.Get(self.name)).constraints return vars(result) if result else result - def get_actions(self, schema=False): + async def get_actions(self, schema=False): """Get actions defined for this application. :param bool schema: Return the full action schema - + :return dict: The charms actions, empty dict if none are defined. """ - raise NotImplementedError() + actions = {} + entity = [{"tag": self.tag}] + action_facade = client.ActionFacade.from_connection(self.connection) + results = ( + await action_facade.ApplicationsCharmsActions(entity)).results + for result in results: + if result.application_tag == self.tag and result.actions: + actions = result.actions + break + if not schema: + actions = {k: v['description'] for k, v in actions.items()} + return actions def get_resources(self, details=False): """Return resources for this application. @@ -252,12 +295,10 @@ class Application(model.ModelEntity): ) return await self.ann_facade.Set([ann]) - async def set_config(self, config, to_default=False): + async def set_config(self, config): """Set configuration options for this application. :param config: Dict of configuration to set - :param bool to_default: Set application options to default values - """ app_facade = client.ApplicationFacade.from_connection(self.connection) @@ -266,6 +307,19 @@ class Application(model.ModelEntity): return await app_facade.Set(self.name, config) + async def reset_config(self, to_default): + """ + Restore application config to default values. + + :param list to_default: A list of config options to be reset to their default value. + """ + app_facade = client.ApplicationFacade.from_connection(self.connection) + + log.debug( + 'Restoring default config for %s: %s', self.name, to_default) + + return await app_facade.Unset(self.name, to_default) + async def set_constraints(self, constraints): """Set machine constraints for this application. @@ -342,8 +396,13 @@ class Application(model.ModelEntity): raise ValueError("switch and revision are mutually exclusive") client_facade = client.ClientFacade.from_connection(self.connection) + resources_facade = client.ResourcesFacade.from_connection( + self.connection) app_facade = client.ApplicationFacade.from_connection(self.connection) + charmstore = self.model.charmstore + charmstore_entity = None + if switch is not None: charm_url = switch if not charm_url.startswith('cs:'): @@ -354,18 +413,65 @@ class Application(model.ModelEntity): if revision is not None: charm_url = "%s-%d" % (charm_url, revision) else: - charmstore = self.model.charmstore - entity = await charmstore.entity(charm_url, channel=channel) - charm_url = entity['Id'] + charmstore_entity = await charmstore.entity(charm_url, + channel=channel) + charm_url = charmstore_entity['Id'] if charm_url == self.data['charm-url']: raise JujuError('already running charm "%s"' % charm_url) + # Update charm await client_facade.AddCharm( url=charm_url, channel=channel ) + # Update resources + if not charmstore_entity: + charmstore_entity = await charmstore.entity(charm_url, + channel=channel) + store_resources = charmstore_entity['Meta']['resources'] + + request_data = [client.Entity(self.tag)] + response = await resources_facade.ListResources(request_data) + existing_resources = { + resource.name: resource + for resource in response.results[0].resources + } + + resources_to_update = [ + resource for resource in store_resources + if resource['Name'] not in existing_resources or + existing_resources[resource['Name']].origin != 'upload' + ] + + if resources_to_update: + request_data = [ + client.CharmResource( + description=resource.get('Description'), + fingerprint=resource['Fingerprint'], + name=resource['Name'], + path=resource['Path'], + revision=resource['Revision'], + size=resource['Size'], + type_=resource['Type'], + origin='store', + ) for resource in resources_to_update + ] + response = await resources_facade.AddPendingResources( + self.tag, + charm_url, + request_data + ) + pending_ids = response.pending_ids + resource_ids = { + resource['Name']: id + for resource, id in zip(resources_to_update, pending_ids) + } + else: + resource_ids = None + + # Update application await app_facade.SetCharm( application=self.entity_id, channel=channel, @@ -374,7 +480,7 @@ class Application(model.ModelEntity): config_settings_yaml=None, force_series=force_series, force_units=force_units, - resource_ids=None, + resource_ids=resource_ids, storage_constraints=None )