async def test_file_cred_v3(self, mock_cf): with NamedTemporaryFile() as tempfile: tempfile.close() temppath = Path(tempfile.name) temppath.write_text('cred-test') cred = client.CloudCredential(auth_type='jsonfile', attrs={'file': tempfile.name}) jujudata = mock.MagicMock() c = Controller(jujudata=jujudata) c._connector = base.AsyncMock() up_creds = base.AsyncMock() cloud_facade = mock_cf.from_connection() cloud_facade.version = 3 cloud_facade.UpdateCredentialsCheckModels = up_creds await c.add_credential( name='name', credential=cred, cloud='cloud', owner='owner', force=True, ) assert up_creds.called assert up_creds.call_args[1]['force'] new_cred = up_creds.call_args[1]['credentials'][0].credential assert cred.attrs['file'] == tempfile.name assert new_cred.attrs['file'] == 'cred-test'
async def test_redirect(event_loop): controller = Controller() await controller.connect() kwargs = controller.connection().connect_params() await controller.disconnect() # websockets.server.logger.setLevel(logging.DEBUG) # websockets.client.logger.setLevel(logging.DEBUG) # # websockets.protocol.logger.setLevel(logging.DEBUG) # logger.setLevel(logging.DEBUG) destination = 'wss://{}/api'.format(kwargs['endpoint']) redirect_statuses = [ http.HTTPStatus.MOVED_PERMANENTLY, http.HTTPStatus.FOUND, http.HTTPStatus.SEE_OTHER, http.HTTPStatus.TEMPORARY_REDIRECT, http.HTTPStatus.PERMANENT_REDIRECT, ] test_server_cert = Path(__file__).with_name('cert.pem') kwargs['cacert'] += '\n' + test_server_cert.read_text() server = RedirectServer(destination, event_loop) try: for status in redirect_statuses: logger.debug('test: starting {}'.format(status)) server.start(status) await run_with_interrupt(server.running.wait(), server.terminated) if server.exception: raise server.exception assert not server.terminated.is_set() logger.debug('test: started') kwargs_copy = dict(kwargs, endpoint='localhost:{}'.format(server.port)) logger.debug('test: connecting') conn = await Connection.connect(**kwargs_copy) logger.debug('test: connected') await conn.close() logger.debug('test: stopping') server.stop() await server.stopped.wait() logger.debug('test: stopped') finally: server.terminate() await server.terminated.wait()
async def test_macaroon_auth(event_loop): jujudata = FileJujuData() account = jujudata.accounts()[jujudata.current_controller()] with base.patch_file('~/.local/share/juju/accounts.yaml'): if 'password' in account: # force macaroon auth by "changing" password to current password result = subprocess.run( ['juju', 'change-user-password'], input='{0}\n{0}\n'.format(account['password']), universal_newlines=True, stderr=subprocess.PIPE) assert result.returncode == 0, ('Failed to change password: '******'{}'.format(result.stderr)) controller = Controller() try: await controller.connect() assert controller.is_connected() finally: if controller.is_connected(): await controller.disconnect() async with base.CleanModel(): pass # create and login to model works
async def test_change_user_password(event_loop): async with base.CleanController() as controller: username = '******'.format(uuid.uuid4()) await controller.add_user(username) await controller.change_user_password(username, 'password') try: new_controller = Controller() await new_controller.connect(controller.connection.endpoint, username, 'password') result = True await new_controller.disconnect() except JujuAPIError: result = False assert result is True
async def test_with_endpoint_and_macaroons(self, mock_connect, mock_update_endpoints): c = Controller() await c.connect(endpoint='0.1.2.3:4566', macaroons=['macaroon']) mock_connect.assert_called_with(endpoint='0.1.2.3:4566', macaroons=['macaroon']) mock_update_endpoints.assert_called_with() await c.connect(endpoint='0.1.2.3:4566', bakery_client='bakery', macaroons=['macaroon']) mock_connect.assert_called_with(endpoint='0.1.2.3:4566', bakery_client='bakery', macaroons=['macaroon']) mock_update_endpoints.assert_called_with()
async def async_cloud(name=None): """Return information about cloud. :param name: Cloud name. If not specified, the cloud where the controller lives on is returned. :type name: Optional[str] :returns: Information on all clouds in the controller. :rtype: CloudResult """ controller = Controller() await controller.connect() cloud = await controller.cloud(name=name) await controller.disconnect() return cloud
async def main(): controller = Controller() print("Connecting to controller") # connect to current controller with current user, per Juju CLI await controller.connect() try: model_name = "addmodeltest-{}".format(uuid.uuid4()) print("Adding model {}".format(model_name)) model = await controller.add_model(model_name) print('Deploying ubuntu') application = await model.deploy( 'ubuntu-10', application_name='ubuntu', series='trusty', channel='stable', ) print('Waiting for active') await asyncio.sleep(10) await model.block_until(lambda: all(unit.workload_status == 'active' for unit in application.units)) print("Verifying that we can ssh into the created model") ret = await utils.execute_process('juju', 'ssh', '-m', model_name, 'ubuntu/0', 'ls /', log=LOG) assert ret print('Removing ubuntu') await application.remove() print("Destroying model") await controller.destroy_model(model.info.uuid) except Exception: LOG.exception( "Test failed! Model {} may not be cleaned up".format(model_name)) finally: print('Disconnecting from controller') if model: await model.disconnect() await controller.disconnect()
async def __aenter__(self): self.controller = Controller() await self.controller.connect_current() model_name = 'model-{}'.format(uuid.uuid4()) self.model = await self.controller.add_model(model_name) # Ensure that we connect to the new model by default. This also # prevents failures if test was started with no current model. self._patch_cm = mock.patch.object(JujuData, 'current_model', return_value=model_name) self._patch_cm.start() return self.model
async def watch(): controller = Controller() # connect to current # controller with current user, per Juju CLI await controller.connect() # Need to call the WatchModelSummaries or WatchAllModelSummaries on the # controller. def callback(summary): print("-- change --\n{}\n".format(summary)) await controller.watch_model_summaries(callback) while True: await asyncio.sleep(1)
async def test_file_cred_v2(self, mock_cf): with NamedTemporaryFile() as tempfile: tempfile.close() temppath = Path(tempfile.name) temppath.write_text('cred-test') cred = client.CloudCredential(auth_type='jsonfile', attrs={'file': tempfile.name}) jujudata = mock.MagicMock() c = Controller(jujudata=jujudata) c._connector = base.AsyncMock() up_creds = base.AsyncMock() cloud_facade = mock_cf.from_connection() cloud_facade.version = 2 cloud_facade.UpdateCredentials = up_creds await c.add_credential( name='name', credential=cred, cloud='cloud', owner='owner', ) assert up_creds.called new_cred = up_creds.call_args[0][0][0].credential assert cred.attrs['file'] == tempfile.name assert new_cred.attrs['file'] == 'cred-test'
async def model_available(): """ Check whether selected model is already available. """ if app.provider.controller is None: raise Exception("No controller selected") if app.provider.model is None: raise Exception("No model selected.") controller = Controller(app.loop) await controller.connect(app.provider.controller) try: models = await controller.list_models() return app.provider.model in models finally: await controller.disconnect()
async def async_add_model(model_name, config=None): """Add a model to the current controller. :param model_name: Name to give the new model. :type model_name: str :param config: Model configuration. :type config: dict """ controller = Controller() await controller.connect() logging.debug("Adding model {}".format(model_name)) model = await controller.add_model(model_name, config=config) # issue/135 It is necessary to disconnect the model here or async spews # tracebacks even during a successful run. await model.disconnect() await controller.disconnect()
async def run(): controller = Controller() await controller.connect_current() model = await controller.add_model( 'libjuju-test', 'cloud-aws', 'cloudcred-aws_tvansteenburgh@external_aws-tim', ) await model.deploy( 'ubuntu-0', service_name='ubuntu', series='trusty', channel='stable', ) await model.disconnect() await controller.disconnect() model.loop.stop()
async def main(): controller = Controller() await controller.connect() model = await controller.add_model( 'my-test-model', 'aws', 'aws-tim', ) await model.deploy( 'ubuntu-0', application_name='ubuntu', series='trusty', channel='stable', ) await model.disconnect() await controller.destroy_model(model.info.uuid) await controller.disconnect()
async def async_add_model(model_name, config=None): """Add a model to the current controller. :param model_name: Name to give the new model. :type model_name: str :param config: Model configuration. :type config: dict """ controller = Controller() await controller.connect() logging.debug("Adding model {}".format(model_name)) model = await controller.add_model(model_name, config=config) await model.disconnect() await controller.disconnect() # NOTE: This is necessary to guarantee juju is aware of the newly created # model. go_list_models()
async def connect(self): """Connect to the Juju controller.""" controller = Controller() log("Connecting to controller... ws://{}:{} as {}/{}".format( self.endpoint, self.port, self.user, self.secret[-4:].rjust(len(self.secret), "*"), )) await controller.connect( endpoint=self.endpoint, username=self.user, password=self.secret, cacert=self.cacert, ) return controller
async def main(): controller = Controller() await controller.connect() try: model = await controller.add_model("test-model") application = await model.deploy("ubuntu", constraints={"arch": "amd64"}) print('Waiting for active') await model.block_until(lambda: all(unit.workload_status == 'active' for unit in application.units)) print("Successfully deployed!") print('Removing bundle') await application.remove() finally: print('Disconnecting from controller') await controller.disconnect() print("Success")
async def create_model(): """ Creates the selected model. """ if app.provider.controller is None: raise Exception("No controller selected") if app.provider.model is None: raise Exception("No model selected.") controller = Controller(app.loop) await controller.connect(app.provider.controller) try: app.juju.client = await controller.add_model( model_name=app.provider.model, cloud_name=app.provider.cloud, region=app.provider.region, credential_name=app.provider.credential) events.ModelConnected.set() finally: await controller.disconnect()
async def test_with_posargs(self, mock_connect, mock_connect_controller): c = Controller() await c.connect('foo') mock_connect_controller.assert_called_once_with('foo') with self.assertRaises(TypeError): await c.connect('endpoint', 'user') await c.connect('endpoint', 'user', 'pass') mock_connect.assert_called_once_with(endpoint='endpoint', username='******', password='******') await c.connect('endpoint', 'user', 'pass', 'cacert', 'bakery', 'macaroons', 'loop', 'max_frame_size') mock_connect.assert_called_with(endpoint='endpoint', username='******', password='******', cacert='cacert', bakery_client='bakery', macaroons='macaroons', loop='loop', max_frame_size='max_frame_size')
async def set_model_acc(c_name, m_name, access, user, username, password, url, port): try: controllers = redis.StrictRedis(host=url, port=port, charset="utf-8", decode_responses=True, db=10) users = redis.StrictRedis(host=url, port=port, charset="utf-8", decode_responses=True, db=11) controller = json.loads(controllers.get(c_name)) usr = json.loads(users.get(user)) for mod in controller['models']: if mod['name'] == m_name: model = Model() await model.connect(controller['endpoints'][0], mod['uuid'], username, password, controller['ca-cert']) await model.grant(user, acl=access) exists_con = False for con in usr['controllers']: if con['name'] == c_name: exists_mod = False exists_con = True for mod in con['models']: if mod['name'] == m_name: mod['access'] = access exists_mod = True break if not exists_mod: con['models'].append({'name': m_name, 'access': access}) if not exists_con: usr['controllers'].append({'name': c_name, 'access': 'login', 'models': [{'name': m_name, 'access': access}]}) contro = Controller() await contro.connect(controller['endpoints'][0], username, password, controller['ca-cert']) await contro.grant(user) await contro.disconnect() logger.info('%s access granted on %s:%s for %s', access, c_name, m_name, user) if access == 'admin' or access == 'write': for key in usr['ssh-keys']: await model.add_ssh_key(user, key) model.disconnect() controllers.set(c_name, json.dumps(controller)) users.set(user, json.dumps(usr)) except Exception: exc_type, exc_value, exc_traceback = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_traceback) for l in lines: logger.error(l)
async def temporary_model(log_dir, timeout=14400, force_cloud=''): ''' Create and destroy a temporary Juju model named cdk-build-upgrade-*. This is an async context, to be used within an `async with` statement. ''' with timeout_for_current_task(timeout): controller = Controller() await controller.connect_current() model_name = 'cdk-build-upgrade-%d' % random.randint(0, 10000) model_config = {'test-mode': True} model = await add_model_via_cli(controller, model_name, model_config, force_cloud) cloud = await controller.get_cloud() if cloud == 'localhost': await asyncify(apply_profile)(model_name) try: async with captured_fail_logs(model, log_dir): await yield_(model) finally: await model.disconnect() await controller.destroy_model(model_name) await controller.disconnect()
async def login(self): """Login to the Juju controller.""" if self.authenticated: return cacert = None self.controller = Controller() self.log.debug("JujuApi: Logging into controller") if self.secret: await self.controller.connect( self.endpoint, self.user, self.secret, cacert, ) else: await self.controller.connect_current() self.authenticated = True self.model = await self.get_model(self.model_name)
async def get_controller(self, name, include_passwords=False): """Get a controller by name. :param str name: Name of controller :param bool include_passwords: Include passwords for accounts The returned controller will try and connect to be ready to use. """ # check if name is in the controllers.yaml controllers = self.jujudata.controllers() assert isinstance(controllers, dict) if name not in controllers: raise JujuError('%s is not among the controllers: %s' % (name, controllers.keys())) # make a new Controller object that's connected to the # controller with the given name controller = Controller() await controller.connect(name) return controller
async def async_destroy_model(model_name): """Remove a model from the current controller. :param model_name: Name of model to remove :type model_name: str """ controller = Controller() try: await controller.connect() logging.info("Destroying model {}".format(model_name)) await controller.destroy_model(model_name, destroy_storage=True, force=True, max_wait=600) # The model ought to be destroyed by now. Let's make sure, and if not, # raise an error. Even if the model has been destroyed, it's still # hangs around in the .list_models() for a little while; retry until it # goes away, or that fails. attempt = 1 while True: logging.info("Waiting for model to be fully destroyed: " "attempt: {}".format(attempt)) remaining_models = await controller.list_models() if model_name not in remaining_models: break await asyncio.sleep(10) attempt += 1 if attempt > 20: raise zaza.utilities.exceptions.DestroyModelFailed( "Destroying model {} failed.".format(model_name)) logging.info("Model {} destroyed.".format(model_name)) finally: try: await controller.disconnect() except Exception as e: logging.error("Couldn't disconnect from model: {}".format(str(e)))
async def main(cloud_name, credential_name): controller = Controller() model = None print('Connecting to controller') # connect to current controller with current user, per Juju CLI await controller.connect() try: print('Adding model') model = await controller.add_model( 'test', cloud_name=cloud_name, credential_name=credential_name) # verify credential print("Verify model's credential: {}".format( model.info.cloud_credential_tag)) # verify we can deploy print('Deploying ubuntu') app = await model.deploy('ubuntu-10') print('Waiting for active') await model.block_until( lambda: app.units and all(unit.workload_status == 'active' for unit in app.units)) print('Removing ubuntu') await app.remove() finally: print('Cleaning up') if model: print('Removing model') model_uuid = model.info.uuid await model.disconnect() await controller.destroy_model(model_uuid) print('Disconnecting') await controller.disconnect()
async def test_controller_connect_no_args(self, mock_connect_controller): from juju.controller import Controller c = Controller() await c.connect() mock_connect_controller.assert_called_once_with(None)
async def test_controller_connect_with_controller_name( self, mock_connect_controller): from juju.controller import Controller c = Controller() await c.connect(controller_name='foo') mock_connect_controller.assert_called_once_with('foo')
async def test_with_endpoint_and_bakery_client(self, mock_connect): c = Controller() await c.connect(endpoint='0.1.2.3:4566', bakery_client='bakery') mock_connect.assert_called_once_with(endpoint='0.1.2.3:4566', bakery_client='bakery')
async def test_with_endpoint_and_no_auth(self, mock_connect): c = Controller() with self.assertRaises(TypeError): await c.connect(endpoint='0.1.2.3:4566') self.assertEqual(mock_connect.call_count, 0)
async def test_no_args(self, mock_connect_controller): c = Controller() await c.connect() mock_connect_controller.assert_called_once_with(None)
async def __aenter__(self): self._controller = Controller() await self._controller.connect() return self._controller
async def main(): controller1 = Controller() print("Connecting to controller") await controller1.connect("test") controller2 = Controller() print("Connecting to controller") await controller2.connect("test2") try: print('Creating models') offering_model = await controller1.add_model('test-cmr-1') consuming_model = await controller2.add_model('test-cmr-2') print('Deploying mysql') application = await offering_model.deploy( 'cs:mysql', application_name='mysql', series='trusty', channel='stable', ) print('Waiting for active') await offering_model.block_until(lambda: all( unit.workload_status == 'active' for unit in application.units)) print('Adding offer') await offering_model.create_offer("mysql:db") offers = await offering_model.list_offers() print( 'Show offers', ', '.join("%s: %s" % item for offer in offers.results for item in vars(offer).items())) print('Consuming offer') await consuming_model.consume("admin/test-cmr-1.mysql", controller_name="test") print('Exporting bundle') with tempfile.TemporaryDirectory() as dirpath: await offering_model.export_bundle("{}/bundle.yaml".format(dirpath) ) print("Remove SAAS") await consuming_model.remove_saas("mysql") print('Removing offer') await offering_model.remove_offer("admin/test-cmr-1.mysql", force=True) print('Destroying models') await controller1.destroy_model(offering_model.info.uuid) await controller2.destroy_model(consuming_model.info.uuid) except Exception: log.exception("Example failed!") raise finally: print('Disconnecting from controller') await controller1.disconnect() await controller2.disconnect()
async def test_with_controller_name(self, mock_connect_controller, mock_update_endpoints): c = Controller() await c.connect(controller_name='foo') mock_connect_controller.assert_called_once_with('foo') mock_update_endpoints.assert_called_once_with()