Skip to content

Commit 3c57a0c

Browse files
authored
Merge pull request #1038 from Aflynn50/fix-consume
#1038 #### Description `consume` takes a `controller_name` argument. This is not needed and should be automatically generated from the offer url. A deprecation warning is logged and the variable is not used. Also update offer and consume integration tests to no longer be skipped. This helps avoid #1031 #### QA Steps ``` juju bootstrap lxd c1 juju add-model offerer juju deploy juju-qa-dummy-source dummy-source juju offer dummy-source:sink juju bootstrap lxd c2 python -m asyncio # In REPL from juju import model m = model.Model() await m.connect() await m.consume("c1:admin/offerer.dummy-source") # Exit REPL juju status # Confirm SAAS exists juju remove-saas dummy-source # Confirm removal python -m asyncio # In REPL from juju import model m = model.Model() await m.connect() await m.consume("admin/offerer.dummy-source", controller_name="c1") # Exit REPL juju status # Confirm SAAS exists juju remove-saas dummy-source # Confirm removal python -m asyncio # In REPL from juju import model m = model.Model() await m.connect() await m.consume("c1:admin/offerer.dummy-source", controller_name="c1") ``` All CI tests need to pass.
2 parents fdf5e3c + 01982c9 commit 3c57a0c

2 files changed

Lines changed: 77 additions & 5 deletions

File tree

juju/model.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,8 +1526,7 @@ async def integrate(self, relation1, relation2):
15261526
remote_endpoint.source = current.controller_name
15271527
# consume the remote endpoint
15281528
await self.consume(remote_endpoint.string(),
1529-
application_alias=remote_endpoint.application,
1530-
controller_name=remote_endpoint.source)
1529+
application_alias=remote_endpoint.application)
15311530

15321531
log.debug(
15331532
'Adding relation %s <-> %s', endpoints[0], endpoints[1])
@@ -2535,7 +2534,12 @@ async def consume(self, endpoint, application_alias="", controller_name=None, co
25352534
"""
25362535
Adds a remote offer to the model. Relations can be created later using
25372536
"juju relate".
2537+
2538+
If consuming a relation from a model on different controller the
2539+
controller name must be included in the endpoint. The controller_name
2540+
argument is being deprecated.
25382541
"""
2542+
25392543
if controller and controller_name:
25402544
raise JujuError("cannot set both controller_name and controller")
25412545
try:
@@ -2549,9 +2553,15 @@ async def consume(self, endpoint, application_alias="", controller_name=None, co
25492553
offer.user = self.info.username
25502554
endpoint = offer.string()
25512555

2552-
source = None
25532556
if controller_name:
2554-
source = await self._get_source_api(offer, controller_name=controller_name)
2557+
log.warning(
2558+
'controller_name argument will soon be deprecated, controller '
2559+
'should be specified in endpoint url')
2560+
if offer.source == "":
2561+
offer.source = controller_name
2562+
2563+
if offer.source:
2564+
source = await self._get_source_api(offer)
25552565
else:
25562566
if controller:
25572567
source = controller
@@ -2766,12 +2776,15 @@ async def revoke_secret(self, secret_name, application, *applications):
27662776
if result_error.error is not None:
27672777
raise JujuAPIError(result_error.error)
27682778

2769-
async def _get_source_api(self, url, controller_name=None):
2779+
async def _get_source_api(self, url):
27702780
controller = Controller()
27712781
if url.has_empty_source():
27722782
async with ConnectedController(self.connection()) as current:
27732783
if current.controller_name is not None:
27742784
controller_name = current.controller_name
2785+
else:
2786+
controller_name = url.source
2787+
27752788
await controller.connect(controller_name=controller_name)
27762789
return controller
27772790

tests/unit/test_offerendpoint.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#
77

88
import unittest
9+
import mock
10+
from juju.model import Model
11+
from juju.controller import Controller
912

1013
from juju.offerendpoints import (LocalEndpoint, OfferEndpoints, OfferURL,
1114
ParseError, maybe_parse_offer_url_source,
@@ -90,3 +93,59 @@ def test_parse_local_endpoint_failures(self):
9093
self.assertEqual(e.message, case)
9194
except Exception:
9295
raise
96+
97+
98+
class TestConsume(unittest.IsolatedAsyncioTestCase):
99+
@mock.patch.object(Model, 'connection')
100+
@mock.patch.object(Controller, 'disconnect')
101+
@mock.patch('juju.model._create_consume_args')
102+
@mock.patch('juju.client.client.ApplicationFacade.from_connection')
103+
async def test_external_controller_consume(self, mock_from_connection,
104+
mock_controller, mock_connection, mock_create_consume_args):
105+
""" Test consuming an offer from an external controller. This would be
106+
better suited as an integration test however pylibjuju does not allow
107+
for bootstrapping of extra controllers.
108+
"""
109+
110+
mock_create_consume_args.return_value = None
111+
mock_connection.return_value = None
112+
113+
mock_consume_details = mock.MagicMock()
114+
mock_consume_details.offer.offer_url = "user/offerer.app"
115+
mock_controller.get_consume_details = mock.AsyncMock(return_value=mock_consume_details)
116+
mock_controller.disconnect = mock.AsyncMock()
117+
118+
mock_facade = mock.MagicMock()
119+
mock_from_connection.return_value = mock_facade
120+
121+
mock_results = mock.MagicMock()
122+
mock_results.results = [mock.MagicMock()]
123+
mock_results.results[0].error = None
124+
mock_facade.Consume = mock.AsyncMock(return_value=mock_results)
125+
126+
m = Model()
127+
m._get_source_api = mock.AsyncMock(return_value=mock_controller)
128+
129+
# Test with an external controller.
130+
offer_url = "externalcontroller:user/offerer.app"
131+
await m.consume(offer_url)
132+
m._get_source_api.assert_called_once_with(parse_offer_url(offer_url))
133+
mock_controller.get_consume_details.assert_called_with("user/offerer.app")
134+
135+
# Test with an external controller and controller_name arg.
136+
offer_url = "externalcontroller:user/offerer.app"
137+
await m.consume(offer_url, controller_name="externalcontroller")
138+
m._get_source_api.assert_called_with(parse_offer_url(offer_url))
139+
mock_controller.get_consume_details.assert_called_with("user/offerer.app")
140+
141+
# Test with a local (mocked) controller.
142+
offer_url = "user/offerer.app"
143+
await m.consume(offer_url, controller=mock_controller)
144+
mock_controller.get_consume_details.assert_called_with("user/offerer.app")
145+
146+
# Test with an external controller with just controller_name. This will
147+
# soon be deprecated.
148+
offer_url = "user/offerer.app"
149+
await m.consume(offer_url, controller_name="externalcontroller")
150+
m._get_source_api.assert_called_with(parse_offer_url("externalcontroller:user/offerer.app"))
151+
mock_controller.get_consume_details.assert_called_with("user/offerer.app")

0 commit comments

Comments
 (0)