def test_welcome_message(self, mock_close_port, mock_open_port): # The welcome message is properly handled. jujushell.build_config({ 'log-level': 'info', 'port': 4247, 'tls': False, 'welcome-message': ' these are\nthe voyages\n\n', }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'info', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 4247, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': 'these are\nthe voyages', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_dns_name_provided_but_tls_not_enabled( self, mock_close_port, mock_open_port): # The provided DNS name is ignored when security is not enabled. jujushell.build_config({ 'dns-name': 'shell.example.com', 'log-level': 'debug', 'port': 8080, 'tls': False, }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 8080, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(8080)
def test_provided_juju_addresses(self, mock_close_port, mock_open_port): # Juju addresses can be provided via the configuration. jujushell.build_config({ 'juju-addrs': '1.2.3.4/provided 4.3.2.1/provided', 'log-level': 'info', 'port': 4247, 'tls': False, }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4/provided', '4.3.2.1/provided'], 'juju-cert': '', 'log-level': 'info', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 4247, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_allowed_users(self, mock_close_port, mock_open_port): # The list of allowed users is properly generated. jujushell.build_config({ 'allowed-users': 'who dalek rose@external', 'log-level': 'info', 'port': 4247, 'tls': False, }) expected_config = { 'allowed-users': ['who', 'dalek', 'rose@external'], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'info', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 4247, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_tls_keys_ignored_when_dns_name_provided( self, mock_close_port, mock_open_port): # The TLS keys and port options are ignored when a DNS name is set. jujushell.build_config({ 'dns-name': 'example.com', 'log-level': 'debug', 'port': 80, 'tls': True, 'tls-cert': base64.b64encode(b'provided cert'), 'tls-key': base64.b64encode(b'provided key'), }) expected_config = { 'allowed-users': [], 'dns-name': 'example.com', 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 443, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertFalse(mock_close_port.called) mock_open_port.assert_called_once_with(443)
def test_juju_cert_from_agent_file(self, mock_close_port, mock_open_port): # A Juju certificate can be retrieved from the agent file in the unit. # Make agent file live in the temp dir. agent = os.path.join(os.environ['CHARM_DIR'], '..', 'agent.conf') with open(agent, 'w') as agentfile: yaml.safe_dump({'cacert': 'agent cert'}, agentfile) jujushell.build_config({ 'log-level': 'info', 'juju-cert': 'from-unit', 'port': 4247, 'tls': False, }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': 'agent cert', 'log-level': 'info', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 4247, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_dns_name_provided(self, mock_close_port, mock_open_port): # The DNS name is propagated to the service when provided. jujushell.build_config({ 'dns-name': 'shell.example.com', 'log-level': 'debug', 'port': 443, 'tls': True, }) expected_config = { 'allowed-users': [], 'dns-name': 'shell.example.com', 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 443, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertFalse(mock_close_port.called) mock_open_port.assert_called_once_with(443)
def test_tls_generated_when_key_is_missing( self, mock_close_port, mock_open_port): # TLS keys are generated if only one key is provided, not both. self.make_cert() with patch('jujushell.call'): jujushell.build_config({ 'log-level': 'trace', 'port': 4247, 'tls': True, 'tls-cert': base64.b64encode(b'provided cert'), 'tls-key': '', }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'trace', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 4247, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'tls-cert': 'my cert', 'tls-key': 'my key', 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_tls_generated_when_key_is_missing(self, mock_close_port, mock_open_port): # TLS keys are generated if only one key is provided, not both. self.make_cert() with patch('jujushell.call'): jujushell.build_config({ 'log-level': 'trace', 'port': 4247, 'tls': True, 'tls-cert': base64.b64encode(b'provided cert'), 'tls-key': '', }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'trace', 'port': 4247, 'profiles': ['default', 'termserver-limited'], 'tls-cert': 'my cert', 'tls-key': 'my key', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_tls_generated(self, mock_close_port, mock_open_port): # TLS keys are generated if not provided. self.make_cert() with patch('jujushell.call') as mock_call: jujushell.build_config({ 'log-level': 'trace', 'port': 4247, 'tls': True, 'tls-cert': '', 'tls-key': '', }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'trace', 'port': 4247, 'profiles': ['default', 'termserver-limited'], 'tls-cert': 'my cert', 'tls-key': 'my key', } self.assertEqual(expected_config, self.get_config()) # The right command has been executed. mock_call.assert_called_once_with('openssl', 'req', '-x509', '-newkey', 'rsa:4096', '-keyout', 'key.pem', '-out', 'cert.pem', '-days', '365', '-nodes', '-subj', '/C=/ST=/L=/O=/OU=/CN=0.0.0.0') # Key files has been removed. self.assertEqual(['files'], os.listdir('.')) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_tls_provided(self, mock_close_port, mock_open_port): # Provided TLS keys are properly used. jujushell.build_config({ 'log-level': 'debug', 'port': 80, 'tls': True, 'tls-cert': base64.b64encode(b'provided cert'), 'tls-key': base64.b64encode(b'provided key'), }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 80, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'tls-cert': 'provided cert', 'tls-key': 'provided key', 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(80)
def test_error_no_juju_addresses(self, mock_close_port, mock_open_port): # A ValueError is raised if no Juju addresses can be retrieved. os.environ['JUJU_API_ADDRESSES'] = '' with self.assertRaises(ValueError) as ctx: jujushell.build_config({ 'log-level': 'info', 'port': 4247, 'tls': False, }) self.assertEqual('could not find API addresses', str(ctx.exception)) self.assertEqual(0, mock_close_port.call_count) self.assertEqual(0, mock_open_port.call_count)
def test_previous_port_closed(self, mock_close_port, mock_open_port): # When changing between ports, the previous one is properly closed. Config = type('Config', (dict, ), {'_prev_dict': None}) config = Config({ 'dns-name': 'shell.example.com', 'log-level': 'debug', 'port': 80, 'tls': True, }) config._prev_dict = { 'log-level': 'debug', 'port': 80, 'tls': True, } jujushell.build_config(config) mock_close_port.assert_called_once_with(80) mock_open_port.assert_called_once_with(443)
def test_no_tls(self, mock_close_port, mock_open_port): # The configuration file is created correctly without TLS. jujushell.build_config({ 'log-level': 'info', 'port': 4247, 'tls': False, }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'info', 'port': 4247, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_tls_generated(self, mock_close_port, mock_open_port): # TLS keys are generated if not provided. self.make_cert() with patch('jujushell.call') as mock_call: jujushell.build_config({ 'log-level': 'trace', 'port': 4247, 'tls': True, 'tls-cert': '', 'tls-key': '', }) expected_config = { 'allowed-users': [], 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'trace', 'lxd-socket-path': '/var/lib/lxd/unix.socket', 'port': 4247, 'profiles': [ jujushell.PROFILE_TERMSERVER, jujushell.PROFILE_TERMSERVER_LIMITED, ], 'session-timeout': 0, 'tls-cert': 'my cert', 'tls-key': 'my key', 'welcome-message': '', } self.assertEqual(expected_config, self.get_config()) # The right command has been executed. mock_call.assert_called_once_with( 'openssl', 'req', '-x509', '-newkey', 'rsa:4096', '-keyout', 'key.pem', '-out', 'cert.pem', '-days', '365', '-nodes', '-subj', '/C=GB/ST=London/L=London/O=Canonical/OU=JAAS/CN=0.0.0.0') # Key files has been removed. self.assertEqual(['files'], os.listdir('.')) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_provided_juju_addresses(self, mock_close_port, mock_open_port): # Juju addresses can be provided via the configuration. jujushell.build_config({ 'juju-addrs': '1.2.3.4/provided 4.3.2.1/provided', 'log-level': 'info', 'port': 4247, 'tls': False, }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4/provided', '4.3.2.1/provided'], 'juju-cert': '', 'log-level': 'info', 'port': 4247, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_dns_name_provided(self, mock_close_port, mock_open_port): # The DNS name is propagated to the service when provided. jujushell.build_config({ 'dns-name': 'shell.example.com', 'log-level': 'debug', 'port': 443, 'tls': True, }) expected_config = { 'dns-name': 'shell.example.com', 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'port': 443, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(443)
def test_dns_name_provided_but_tls_not_enabled(self, mock_close_port, mock_open_port): # The provided DNS name is ignored when security is not enabled. jujushell.build_config({ 'dns-name': 'shell.example.com', 'log-level': 'debug', 'port': 8080, 'tls': False, }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'port': 8080, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(8080)
def test_tls_keys_provided_but_tls_not_enabled(self, mock_close_port, mock_open_port): # Provided TLS keys are ignored when security is not enabled. jujushell.build_config({ 'log-level': 'debug', 'port': 80, 'tls': False, 'tls-cert': base64.b64encode(b'provided cert'), 'tls-key': base64.b64encode(b'provided key'), }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'port': 80, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(80)
def test_juju_cert_from_agent_file(self, mock_close_port, mock_open_port): # A Juju certificate can be retrieved from the agent file in the unit. # Make agent file live in the temp dir. agent = os.path.join(os.environ['CHARM_DIR'], '..', 'agent.conf') with open(agent, 'w') as agentfile: yaml.safe_dump({'cacert': 'agent cert'}, agentfile) jujushell.build_config({ 'log-level': 'info', 'juju-cert': 'from-unit', 'port': 4247, 'tls': False, }) expected_config = { 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': 'agent cert', 'log-level': 'info', 'port': 4247, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(4247)
def test_tls_keys_ignored_when_dns_name_provided(self, mock_close_port, mock_open_port): # The TLS keys and port options are ignored when a DNS name is set. jujushell.build_config({ 'dns-name': 'example.com', 'log-level': 'debug', 'port': 80, 'tls': True, 'tls-cert': base64.b64encode(b'provided cert'), 'tls-key': base64.b64encode(b'provided key'), }) expected_config = { 'dns-name': 'example.com', 'image-name': 'termserver', 'juju-addrs': ['1.2.3.4:17070', '4.3.2.1:17070'], 'juju-cert': '', 'log-level': 'debug', 'port': 443, 'profiles': ['default', 'termserver-limited'], } self.assertEqual(expected_config, self.get_config()) self.assertEqual(0, mock_close_port.call_count) mock_open_port.assert_called_once_with(443)