def make_clients(self): config = {'type': 'aws', 'region': 'east', 'name': 'model-a'} env = JujuData('model-a', config, juju_home='foo') env.user_name = 'me' source_client = fake_juju_client(env) dest_client = fake_juju_client(env) return source_client, dest_client
def main(): parser = ArgumentParser(description=dedent('''\ Convert environments.yaml to 2.0 format. environments.yaml from JUJU_HOME will be used. Existing configs in the output directory will be overwritten. Does not support configs of type 'local'. ''')) parser.add_argument('config_dir', metavar='OUTPUT_DIR', help='Directory to write updated configs to.') args = parser.parse_args() clouds_credentials = JujuData('', {}) clouds_credentials.load_yaml() for environment, config in get_environments().items(): if config['type'] == 'local': continue env = JujuData(environment, config) env.clouds = clouds_credentials.clouds env.credentials = clouds_credentials.credentials print(environment) sys.stdout.flush() out_path = os.path.join(args.config_dir, '{}.yaml'.format(environment)) with open(out_path, 'w') as out_file: write_new_config(env, out_file)
def test_background_chaos(self): client = ModelClient(JujuData('foo', {}), None, '/foo/juju') with patch('chaos.MonkeyRunner.deploy_chaos_monkey', autospec=True) as d_mock: with patch('chaos.MonkeyRunner.unleash_once', return_value=['1'], autospec=True) as u_mock: with patch('chaos.MonkeyRunner.wait_for_chaos', autospec=True) as w_mock: with patch('chaos.remote_from_unit', return_value=SSHRemote(None, None, 'foo')) as ru_mock: with patch('remote.SSHRemote.copy') as rc_mock: log_dir = mkdtemp() with background_chaos('foo', client, log_dir, 1): pass rmtree(log_dir) self.assertEqual(1, d_mock.call_count) self.assertEqual(1, u_mock.call_count) self.assertEqual(1, ru_mock.call_count) self.assertEqual(1, rc_mock.call_count) self.assertEqual({'state': 'start'}, w_mock.mock_calls[0][2]) self.assertEqual({ 'state': 'complete', 'timeout': 1 }, w_mock.mock_calls[1][2])
def test_run_with_unit_fallback(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" with patch.object(client, "get_status") as st: st.return_value = Status.from_text(self.precise_status_output) remote = remote_from_unit(client, unit) with patch.object(client, "get_juju_output") as mock_gjo: mock_gjo.side_effect = subprocess.CalledProcessError(255, "ssh", output="") with patch.object(remote, "_run_subprocess") as mock_run: mock_run.return_value = "contents of /a/file" output = remote.run("cat /a/file") self.assertEqual(output, "contents of /a/file") mock_gjo.assert_called_once_with("ssh", unit, "cat /a/file", timeout=120) mock_run.assert_called_once_with([ "ssh", "-o", "User ubuntu", "-o", "UserKnownHostsFile /dev/null", "-o", "StrictHostKeyChecking no", "-o", "PasswordAuthentication no", "10.55.60.1", "cat /a/file", ]) self.assertRegexpMatches( self.log_stream.getvalue(), "(?m)^WARNING juju ssh to 'a-application/0' failed, .*")
def test_checks_deadline(self): client = ModelClient(JujuData('local', juju_home=''), None, None) with client_past_deadline(client): with patch.object(client, 'get_controller_client', autospec=True): with self.assertRaises(SoftDeadlineExceeded): amm._wait_for_model_check(client, lambda x: 'test', timeout=60)
def isalive(self): juju_data = JujuData('foo', juju_home=self.juju_home) juju_data.load_yaml() creds = juju_data.credentials.setdefault('credentials', {}) creds.update({self.cloud: { 'default-region': self.extra_env['OS_REGION_NAME'], self.extra_env['OS_USERNAME']: { 'domain-name': '', 'user-domain-name': '', 'project-domain-name': '', 'auth-type': 'userpass', 'username': self.extra_env['OS_USERNAME'], 'password': self.extra_env['OS_PASSWORD'], 'tenant-name': self.extra_env['OS_TENANT_NAME'], }}}) juju_data.dump_yaml(self.juju_home, {}) return False
def test_remote_from_unit_with_series(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" remote = remote_from_unit(client, unit, series="trusty") self.assertEqual(repr(remote), "<SSHRemote env='an-env' unit='a-application/0'>") self.assertIs(False, remote.is_windows())
def test_generate_parameters_lxd(self): client = fake_juju_client( env=JujuData('steve', config={'type': 'lxd'})) client.bootstrap() client.juju('add-machine', ()) with self.assertRaisesRegex(InvalidActionError, 'Not supported on LXD provider.'): AddRemoveManyContainerAction.generate_parameters( client, client.get_status())
def test_remote_from_unit(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" with patch.object(client, "get_status", autospec=True) as st: st.return_value = Status.from_text(self.precise_status_output) remote = remote_from_unit(client, unit) self.assertEqual(repr(remote), "<SSHRemote env='an-env' unit='a-application/0'>") self.assertIs(False, remote.is_windows())
def test_remote_from_unit_with_status(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" status = Status.from_text(self.win2012hvr2_status_output) remote = remote_from_unit(client, unit, status=status) self.assertEqual( repr(remote), "<WinRmRemote env='an-env' unit='a-application/0'" " addr='10.55.60.2'>") self.assertIs(True, remote.is_windows())
def test_iter_chaos_monkey_units(self): def output(*args, **kwargs): status = yaml.safe_dump({ 'machines': { '0': { 'agent-state': 'started' } }, 'applications': { 'jenkins': { 'units': { 'foo': { 'subordinates': { 'chaos-monkey/0': { 'baz': 'qux' }, 'not-chaos/0': { 'qwe': 'rty' }, } }, 'bar': { 'subordinates': { 'chaos-monkey/1': { 'abc': '123' }, } } } } } }) output = { ('show-status', '--format', 'yaml'): status, } return output[args] client = ModelClient(JujuData('foo', {}), None, '/foo/juju') runner = MonkeyRunner('foo', client, service='jenkins') with patch.object(client, 'get_juju_output', side_effect=output, autospec=True): monkey_units = dict( (k, v) for k, v in runner.iter_chaos_monkey_units()) expected = { 'chaos-monkey/0': { 'baz': 'qux' }, 'chaos-monkey/1': { 'abc': '123' } } self.assertEqual(expected, monkey_units)
def test_iter_steps_quickstart_fail(self): client = ModelClient( JujuData('foo', {'type': 'local'}), '1.234-76', None) bs_manager = FakeBootstrapManager(client) quickstart = QuickstartTest(bs_manager, '/tmp/bundle.yaml', 2) step_iter = quickstart.iter_steps() with patch.object(client, 'quickstart', side_effect=Exception): with self.assertRaises(Exception): step_iter.next() self.assertIs(False, bs_manager.entered_runtime) self.assertIs(True, bs_manager.exited_bootstrap) self.assertIs(True, bs_manager.exited_top)
def main(): parser = ArgumentParser( description=dedent('''\ Convert environments.yaml to 2.0 format. environments.yaml from JUJU_HOME will be used. Existing configs in the output directory will be overwritten. Does not support configs of type 'local'. ''')) parser.add_argument('config_dir', metavar='OUTPUT_DIR', help='Directory to write updated configs to.') args = parser.parse_args() clouds_credentials = JujuData('', {}) clouds_credentials.load_yaml() for environment, config in get_environments().items(): if config['type'] == 'local': continue env = JujuData(environment, config) env.clouds = clouds_credentials.clouds env.credentials = clouds_credentials.credentials print(environment) sys.stdout.flush() out_path = os.path.join(args.config_dir, '{}.yaml'.format(environment)) with open(out_path, 'w') as out_file: write_new_config(env, out_file)
def test_run_with_unit(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" remote = remote_from_unit(client, unit, series="trusty") with patch.object(client, "get_juju_output") as mock_cmd: mock_cmd.return_value = "contents of /a/file" output = remote.run("cat /a/file") self.assertEqual(output, "contents of /a/file") mock_cmd.assert_called_once_with("ssh", unit, "cat /a/file", timeout=120)
def test_generate_parameters_container_max_10(self): client = fake_juju_client( env=JujuData('steve', config={ 'type': 'not-lxd', 'region': 'asdf' })) client.bootstrap() client.juju('add-machine', ()) status = client.get_status() set_hardware(status.status['machines']['0'], root_disk=2048) with self.assertRaisesRegex(InvalidActionError, 'No space for containers.'): AddRemoveManyContainerAction.generate_parameters(client, status)
def test_basic_args(self): args = ['bundles', 'an-env', '/bin/juju', 'logs', 'deployer-env'] env = JujuData('an-env') client = ModelClient(env, '1.234-76', None) with patch('run_deployer.client_from_config', return_value=client) as c_mock: with patch('run_deployer.boot_context'): with patch('run_deployer.assess_deployer') as ad_mock: main(args) c_mock.assert_called_once_with('an-env', '/bin/juju', debug=False, soft_deadline=None) ad_mock.assert_called_once_with(parse_args(args), client, 1200, 1800)
def test_is_healthy_fail(self): SCRIPT = """#!/bin/bash\necho -n 'FAIL'\nexit 1""" client = ModelClient(JujuData('foo', {}), None, '/foo/juju') with NamedTemporaryFile(delete=False) as health_script: health_script.write(SCRIPT) os.fchmod(health_script.fileno(), stat.S_IEXEC | stat.S_IREAD) health_script.close() monkey_runner = MonkeyRunner('foo', client, health_checker=health_script.name) with patch('logging.error') as le_mock: result = monkey_runner.is_healthy() os.unlink(health_script.name) self.assertFalse(result) self.assertEqual(le_mock.call_args[0][0], 'FAIL')
def fake_juju_client(env=None, full_path=None, debug=False, version='2.0.0', _backend=None, cls=ModelClient, juju_home=None): if juju_home is None: if env is None or env.juju_home is None: juju_home = 'foo' else: juju_home = env.juju_home if env is None: env = JujuData('name', { 'type': 'foo', 'default-series': 'angsty', 'region': 'bar', }, juju_home=juju_home) env.credentials = {'credentials': {'foo': {'creds': {}}}} if _backend is None: backend_state = FakeControllerState() _backend = FakeBackend( backend_state, version=version, full_path=full_path, debug=debug) _backend.set_feature('jes', True) client = cls( env, version, full_path, juju_home, debug, _backend=_backend) client.bootstrap_replaces = {} return client
def test_background_chaos_exits(self): client = ModelClient(JujuData('foo', {}), None, '/foo/juju') with patch('chaos.MonkeyRunner.deploy_chaos_monkey', autospec=True): with patch('chaos.MonkeyRunner.unleash_once', autospec=True): with patch('chaos.MonkeyRunner.wait_for_chaos', autospec=True): with patch('chaos.remote_from_unit'): with patch('remote.SSHRemote.copy'): with patch('logging.exception') as le_mock: with patch('sys.exit', autospec=True) as sm: log_dir = mkdtemp() with background_chaos( 'foo', client, log_dir, 1): raise Exception() rmtree(log_dir) self.assertEqual(1, le_mock.call_count) sm.assert_called_once_with(1)
def test_wait_for_chaos_started(self): client = ModelClient(JujuData('foo', {}), None, '/foo') runner = MonkeyRunner('foo', client) units = [('blib', 'blab')] with patch.object(runner, 'iter_chaos_monkey_units', autospec=True, return_value=units) as ic_mock: with patch.object(runner, 'get_unit_status', autospec=True, return_value='running') as us_mock: returned = runner.wait_for_chaos(state='start') self.assertEqual(returned, None) self.assertEqual(ic_mock.call_count, 1) self.assertEqual(us_mock.call_count, 1)
def test_cat_on_windows(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" with patch.object(client, "get_status", autospec=True) as st: st.return_value = Status.from_text(self.win2012hvr2_status_output) response = winrm.Response(("contents of /a/file", "", 0)) remote = remote_from_unit(client, unit) with patch.object(remote.session, "run_cmd", autospec=True, return_value=response) as mock_run: output = remote.cat("/a/file") self.assertEqual(output, "contents of /a/file") st.assert_called_once_with() mock_run.assert_called_once_with("type", ["/a/file"])
def test_generate_parameters_container_max_10(self): client = fake_juju_client( env=JujuData('steve', config={ 'type': 'not-lxd', 'region': 'asdf' })) client.bootstrap() client.juju('add-machine', ()) status = client.get_status() set_hardware(status.status['machines']['0'], root_disk=32768) params = AddRemoveManyContainerAction.generate_parameters( client, status) self.assertEqual({ 'machine_id': '0', 'container_count': 10, }, params)
def test_deploy_chaos_monkey(self): def output(*args, **kwargs): status = yaml.safe_dump({ 'machines': { '0': { 'agent-state': 'started' } }, 'applications': { 'ser1': { 'units': { 'bar': { 'agent-state': 'started', 'subordinates': { 'chaos-monkey/1': { 'agent-state': 'started' } } } } } } }) output = { ('show-status', '--format', 'yaml'): status, } return output[args] client = ModelClient(JujuData('foo', {}), '1.25.0', '/foo/juju') with patch.object(client, 'get_juju_output', side_effect=output, autospec=True) as gjo_mock: with patch('subprocess.check_call', autospec=True) as cc_mock: monkey_runner = MonkeyRunner('foo', client, service='ser1') with patch('jujupy.client.GroupReporter._write', autospec=True): monkey_runner.deploy_chaos_monkey() assert_juju_call(self, cc_mock, client, ('juju', '--show-log', 'deploy', '-m', 'foo:foo', 'local:chaos-monkey'), 0) assert_juju_call(self, cc_mock, client, ('juju', '--show-log', 'add-relation', '-m', 'foo:foo', 'ser1', 'chaos-monkey'), 1) self.assertEqual(cc_mock.call_count, 2) self.assertEqual(gjo_mock.call_count, 2)
def test_is_healthy_with_no_execute_perms(self): SCRIPT = """#!/bin/bash\nexit 0""" client = ModelClient(JujuData('foo', {}), None, '/foo/juju') with NamedTemporaryFile(delete=False) as health_script: health_script.write(SCRIPT) os.fchmod(health_script.fileno(), stat.S_IREAD) health_script.close() monkey_runner = MonkeyRunner('foo', client, health_checker=health_script.name) with patch('logging.error') as le_mock: with self.assertRaises(OSError): monkey_runner.is_healthy() os.unlink(health_script.name) self.assertRegexpMatches( le_mock.call_args[0][0], r'The health check failed to execute with: \[Errno 13\].*')
def test_run_finally(self): do_finally = MagicMock() def fake_iter_steps(): try: yield {'bootstrap_host': 'foo'} finally: do_finally() client = ModelClient( JujuData('foo', {'type': 'local'}), '1.234-76', None) bs_manager = make_bootstrap_manager(client) quickstart = QuickstartTest(bs_manager, '/tmp/bundle.yaml', 2) with patch.object(quickstart, 'iter_steps', side_effect=fake_iter_steps): quickstart.run() do_finally.assert_called_once_with()
def test_run_cmd(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" with patch.object(client, "get_status", autospec=True) as st: st.return_value = Status.from_text(self.win2012hvr2_status_output) response = winrm.Response(("some out", "some err", 0)) remote = remote_from_unit(client, unit) with patch.object(remote.session, "run_cmd", autospec=True, return_value=response) as mock_run: output = remote.run_cmd( ["C:\\Program Files\\bin.exe", "/IN", "Bob's Stuff"]) self.assertEqual(output, response) st.assert_called_once_with() mock_run.assert_called_once_with('"C:\\Program Files\\bin.exe"', ['/IN "Bob\'s Stuff"'])
def test_run_exception(self): tear_down = MagicMock() def fake_iter_steps(): try: yield {'bootstrap_host': 'foo'} except: tear_down() client = ModelClient( JujuData('foo', {'type': 'local'}), '1.234-76', None) bs_manager = make_bootstrap_manager(client) quickstart = QuickstartTest(bs_manager, '/tmp/bundle.yaml', 2) with patch.object(quickstart, 'iter_steps', side_effect=fake_iter_steps): with self.assertRaises(BaseException): with patch('logging.info', side_effect=Exception): quickstart.run() tear_down.assert_called_once_with()
def test_storage_2_2_with_aws(self): mock_client = Mock(spec=[ "juju", "wait_for_started", "create_storage_pool", "remove_service", "list_storage_pool", "deploy", "get_juju_output", "add_storage", "list_storage", "is_juju1x" ]) mock_client.series = 'trusty' mock_client.version = '2.2' mock_client.is_juju1x.return_value = False mock_client.env = JujuData('foo', {'type': 'ec2'}, 'data') expected_pool = dict(AWS_DEFAULT_STORAGE_POOL_DETAILS) expected_pool.update(storage_pool_details) aws_pool = dict(expected_pool) aws_pool['filesystems'] = {'0/0': 'baz'} aws_pool['Volume'] = '' mock_client.list_storage_pool.side_effect = [json.dumps(aws_pool)] mock_client.list_storage.side_effect = self.make_expected_list_storage( mock_client) assess_storage(mock_client, mock_client.series)
def test_run_default_command_error_fallback(self): env = JujuData("an-env", {"type": "nonlocal"}) client = ModelClient(env, None, None) unit = "a-application/0" error = subprocess.CalledProcessError(1, "ssh", output="bad command") with patch.object(client, "get_status") as st: st.return_value = Status.from_text(self.precise_status_output) remote = remote_from_unit(client, unit) with patch.object(client, "get_juju_output") as mock_gjo: mock_gjo.side_effect = error with self.assertRaises(subprocess.CalledProcessError) as c: remote.run("cat /a/file") self.assertIs(c.exception, error) mock_gjo.assert_called_once_with("ssh", unit, "cat /a/file", timeout=120) self.assertRegexpMatches( self.log_stream.getvalue(), "(?m)^WARNING juju ssh to 'a-application/0' failed, .*")
def test_iter_steps(self): log_dir = use_context(self, temp_dir()) client = ModelClient( JujuData('foo', {'type': 'local'}), '1.234-76', None) bs_manager = make_bootstrap_manager(client, log_dir=log_dir) quickstart = QuickstartTest(bs_manager, '/tmp/bundle.yaml', 2) steps = quickstart.iter_steps() with patch.object(client, 'quickstart') as qs_mock: # Test first yield with patch('jujupy.client.check_free_disk_space', autospec=True): with patch.object(client, 'kill_controller', autospec=True) as kill_mock: step = steps.next() kill_mock.assert_called_once_with() qs_mock.assert_called_once_with('/tmp/bundle.yaml') expected = {'juju-quickstart': 'Returned from quickstart'} self.assertEqual(expected, step) with patch('deploy_stack.get_machine_dns_name', return_value='mocked_name') as dns_mock: # Test second yield with patch.object(client, 'get_controller_client') as gcc_mock: step = steps.next() dns_mock.assert_called_once_with(gcc_mock.return_value, '0') self.assertEqual('mocked_name', step['bootstrap_host']) with patch.object(client, 'wait_for_deploy_started') as wds_mock: # Test third yield step = steps.next() wds_mock.assert_called_once_with(2) self.assertEqual('Deploy stated', step['deploy_started']) with patch.object(client, 'wait_for_started') as ws_mock: # Test forth yield step = steps.next() ws_mock.assert_called_once_with(ANY) self.assertEqual('All Agents started', step['agents_started']) with patch('deploy_stack.safe_print_status'): with patch('deploy_stack.BootstrapManager.tear_down'): with patch('quickstart_deploy.BootstrapManager.dump_all_logs'): with patch('jujupy.ModelClient.iter_model_clients', return_value=[]): steps.close()
def test_basic_args_native_deploy_landscape(self): args = [ 'cs:~landscape/bundle/landscape-scalable', 'an-env', '/bin/juju', 'logs', 'deployer-env', '--allow-native-deploy', '--bundle-verification-script', 'verify_landscape_bundle.py' ] env = JujuData('an-env') client = ModelClient(env, '1.234-76', None) with patch('run_deployer.client_from_config', return_value=client) as c_mock: with patch('run_deployer.boot_context'): with patch('run_deployer.assess_deployer') as ad_mock: with patch('run_deployer.run_command') as rc: main(args) c_mock.assert_called_once_with('an-env', '/bin/juju', debug=False, soft_deadline=None) ad_mock.assert_called_once_with(parse_args(args), client, 1200, 1800) client_ser = pickle.dumps(client) rc.assert_called_once_with(['verify_landscape_bundle.py', client_ser])
def test_suppresses_deadline(self): client = ModelClient(JujuData('local', juju_home=''), None, None) with client_past_deadline(client): real_check_timeouts = client.check_timeouts def get_models(): with real_check_timeouts(): return {'models': [{'name': 'TestModelName'}]} controller_client = Mock() controller_client.get_models.side_effect = get_models with patch.object(client, 'get_controller_client', autospec=True, return_value=controller_client): with patch.object(client, 'check_timeouts', autospec=True): amm._wait_for_model_check(client, lambda x: 'test', timeout=60)