github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/acceptancetests/repository/trusty/haproxy/hooks/tests/test_helpers.py (about) 1 import base64 2 import os 3 4 from contextlib import contextmanager 5 from StringIO import StringIO 6 7 from testtools import TestCase 8 from mock import patch, call, MagicMock 9 10 import hooks 11 from utils_for_tests import patch_open 12 13 14 class HelpersTest(TestCase): 15 16 @patch('hooks.has_ssl_support') 17 @patch('hooks.config_get') 18 def test_creates_haproxy_globals(self, config_get, has_ssl_support): 19 config_get.return_value = { 20 'global_log': 'foo-log, bar-log', 21 'global_maxconn': 123, 22 'global_user': 'foo-user', 23 'global_group': 'foo-group', 24 'global_spread_checks': 234, 25 'global_default_dh_param': 345, 26 'global_default_bind_ciphers': "my:ciphers", 27 'global_debug': False, 28 'global_quiet': False, 29 'global_stats_socket': True, 30 } 31 has_ssl_support.return_value = True 32 result = hooks.create_haproxy_globals() 33 34 sock_path = "/var/run/haproxy/haproxy.sock" 35 expected = '\n'.join([ 36 'global', 37 ' log foo-log', 38 ' log bar-log', 39 ' maxconn 123', 40 ' user foo-user', 41 ' group foo-group', 42 ' spread-checks 234', 43 ' tune.ssl.default-dh-param 345', 44 ' ssl-default-bind-ciphers my:ciphers', 45 ' stats socket %s mode 0600' % sock_path, 46 ]) 47 self.assertEqual(result, expected) 48 49 @patch('hooks.has_ssl_support') 50 @patch('hooks.config_get') 51 def test_creates_haproxy_globals_quietly_with_debug( 52 self, config_get, has_ssl_support): 53 config_get.return_value = { 54 'global_log': 'foo-log, bar-log', 55 'global_maxconn': 123, 56 'global_user': 'foo-user', 57 'global_group': 'foo-group', 58 'global_spread_checks': 234, 59 'global_default_dh_param': 345, 60 'global_default_bind_ciphers': "my:ciphers", 61 'global_debug': True, 62 'global_quiet': True, 63 'global_stats_socket': False, 64 } 65 has_ssl_support.return_value = True 66 result = hooks.create_haproxy_globals() 67 68 expected = '\n'.join([ 69 'global', 70 ' log foo-log', 71 ' log bar-log', 72 ' maxconn 123', 73 ' user foo-user', 74 ' group foo-group', 75 ' debug', 76 ' quiet', 77 ' spread-checks 234', 78 ' tune.ssl.default-dh-param 345', 79 ' ssl-default-bind-ciphers my:ciphers', 80 ]) 81 self.assertEqual(result, expected) 82 83 @patch('hooks.has_ssl_support') 84 @patch('hooks.config_get') 85 def test_creates_haproxy_globals_no_ssl_support( 86 self, config_get, has_ssl_support): 87 config_get.return_value = { 88 'global_log': 'foo-log, bar-log', 89 'global_maxconn': 123, 90 'global_user': 'foo-user', 91 'global_group': 'foo-group', 92 'global_spread_checks': 234, 93 'global_debug': False, 94 'global_quiet': False, 95 'global_stats_socket': True, 96 } 97 has_ssl_support.return_value = False 98 result = hooks.create_haproxy_globals() 99 100 sock_path = "/var/run/haproxy/haproxy.sock" 101 expected = '\n'.join([ 102 'global', 103 ' log foo-log', 104 ' log bar-log', 105 ' maxconn 123', 106 ' user foo-user', 107 ' group foo-group', 108 ' spread-checks 234', 109 ' stats socket %s mode 0600' % sock_path, 110 ]) 111 self.assertEqual(result, expected) 112 113 def test_enables_haproxy(self): 114 mock_file = MagicMock() 115 116 @contextmanager 117 def mock_open(*args, **kwargs): 118 yield mock_file 119 120 initial_content = """ 121 foo 122 ENABLED=0 123 bar 124 """ 125 ending_content = initial_content.replace('ENABLED=0', 'ENABLED=1') 126 127 with patch('__builtin__.open', mock_open): 128 mock_file.read.return_value = initial_content 129 130 hooks.enable_haproxy() 131 132 mock_file.write.assert_called_with(ending_content) 133 134 @patch('hooks.config_get') 135 def test_creates_haproxy_defaults(self, config_get): 136 config_get.return_value = { 137 'default_options': 'foo-option, bar-option', 138 'default_timeouts': '234, 456', 139 'default_log': 'foo-log', 140 'default_mode': 'foo-mode', 141 'default_retries': 321, 142 } 143 result = hooks.create_haproxy_defaults() 144 145 expected = '\n'.join([ 146 'defaults', 147 ' log foo-log', 148 ' mode foo-mode', 149 ' option foo-option', 150 ' option bar-option', 151 ' retries 321', 152 ' timeout 234', 153 ' timeout 456', 154 ]) 155 self.assertEqual(result, expected) 156 157 def test_returns_none_when_haproxy_config_doesnt_exist(self): 158 self.assertIsNone(hooks.load_haproxy_config('/some/foo/file')) 159 160 @patch('__builtin__.open') 161 @patch('os.path.isfile') 162 def test_loads_haproxy_config_file(self, isfile, mock_open): 163 content = 'some content' 164 config_file = '/etc/haproxy/haproxy.cfg' 165 file_object = StringIO(content) 166 isfile.return_value = True 167 mock_open.return_value = file_object 168 169 result = hooks.load_haproxy_config() 170 171 self.assertEqual(result, content) 172 isfile.assert_called_with(config_file) 173 mock_open.assert_called_with(config_file) 174 175 @patch('hooks.load_haproxy_config') 176 def test_gets_monitoring_password(self, load_haproxy_config): 177 load_haproxy_config.return_value = 'stats auth foo:bar' 178 179 password = hooks.get_monitoring_password() 180 181 self.assertEqual(password, 'bar') 182 183 @patch('hooks.load_haproxy_config') 184 def test_gets_none_if_different_pattern(self, load_haproxy_config): 185 load_haproxy_config.return_value = 'some other pattern' 186 187 password = hooks.get_monitoring_password() 188 189 self.assertIsNone(password) 190 191 def test_gets_none_pass_if_config_doesnt_exist(self): 192 password = hooks.get_monitoring_password('/some/foo/path') 193 194 self.assertIsNone(password) 195 196 @patch('hooks.load_haproxy_config') 197 def test_gets_service_ports(self, load_haproxy_config): 198 load_haproxy_config.return_value = ''' 199 listen foo.internal 1.2.3.4:123 200 listen bar.internal 1.2.3.5:234 201 ''' 202 203 ports = hooks.get_service_ports() 204 205 self.assertEqual(ports, (123, 234)) 206 207 @patch('hooks.load_haproxy_config') 208 def test_get_listen_stanzas(self, load_haproxy_config): 209 load_haproxy_config.return_value = ''' 210 listen foo.internal 1.2.3.4:123 211 listen bar.internal 1.2.3.5:234 212 ''' 213 214 stanzas = hooks.get_listen_stanzas() 215 216 self.assertEqual((('foo.internal', '1.2.3.4', 123), 217 ('bar.internal', '1.2.3.5', 234)), 218 stanzas) 219 220 @patch('hooks.load_haproxy_config') 221 def test_get_listen_stanzas_with_frontend(self, load_haproxy_config): 222 load_haproxy_config.return_value = ''' 223 frontend foo-2-123 224 bind 1.2.3.4:123 225 default_backend foo.internal 226 frontend foo-2-234 227 bind 1.2.3.5:234 228 default_backend bar.internal 229 ''' 230 231 stanzas = hooks.get_listen_stanzas() 232 233 self.assertEqual((('foo.internal', '1.2.3.4', 123), 234 ('bar.internal', '1.2.3.5', 234)), 235 stanzas) 236 237 @patch('hooks.load_haproxy_config') 238 def test_get_listen_stanzas_with_ssl_frontend(self, load_haproxy_config): 239 load_haproxy_config.return_value = ''' 240 frontend foo-2-123 241 bind 1.2.3.4:123 ssl crt /foo/bar no-sslv3 242 default_backend foo.internal 243 frontend foo-2-234 244 bind 1.2.3.5:234 245 default_backend bar.internal 246 ''' 247 248 stanzas = hooks.get_listen_stanzas() 249 250 self.assertEqual((('foo.internal', '1.2.3.4', 123), 251 ('bar.internal', '1.2.3.5', 234)), 252 stanzas) 253 254 @patch('hooks.load_haproxy_config') 255 def test_get_empty_tuple_when_no_stanzas(self, load_haproxy_config): 256 load_haproxy_config.return_value = ''' 257 ''' 258 259 stanzas = hooks.get_listen_stanzas() 260 261 self.assertEqual((), stanzas) 262 263 @patch('hooks.load_haproxy_config') 264 def test_get_listen_stanzas_none_configured(self, load_haproxy_config): 265 load_haproxy_config.return_value = "" 266 267 stanzas = hooks.get_listen_stanzas() 268 269 self.assertEqual((), stanzas) 270 271 def test_gets_no_ports_if_config_doesnt_exist(self): 272 ports = hooks.get_service_ports('/some/foo/path') 273 self.assertEqual((), ports) 274 275 @patch('hooks.open_port') 276 @patch('hooks.close_port') 277 def test_updates_service_ports(self, close_port, open_port): 278 old_service_ports = [123, 234, 345] 279 new_service_ports = [345, 456, 567] 280 281 hooks.update_service_ports(old_service_ports, new_service_ports) 282 283 self.assertEqual(close_port.mock_calls, [call(123), call(234)]) 284 self.assertEqual(open_port.mock_calls, 285 [call(456), call(567)]) 286 287 @patch('hooks.open_port') 288 @patch('hooks.close_port') 289 def test_updates_none_if_service_ports_not_provided(self, close_port, 290 open_port): 291 hooks.update_service_ports() 292 293 self.assertFalse(close_port.called) 294 self.assertFalse(open_port.called) 295 296 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 297 def test_creates_a_listen_stanza(self): 298 service_name = 'some-name' 299 service_ip = '10.11.12.13' 300 service_port = 1234 301 service_options = ('foo', 'bar') 302 server_entries = [ 303 ('name-1', 'ip-1', 'port-1', ('foo1', 'bar1')), 304 ('name-2', 'ip-2', 'port-2', ('foo2', 'bar2')), 305 ] 306 307 result = hooks.create_listen_stanza(service_name, service_ip, 308 service_port, service_options, 309 server_entries) 310 311 expected = '\n'.join(( 312 'frontend haproxy-2-1234', 313 ' bind 10.11.12.13:1234', 314 ' default_backend some-name', 315 '', 316 'backend some-name', 317 ' foo', 318 ' bar', 319 ' server name-1 ip-1:port-1 foo1 bar1', 320 ' server name-2 ip-2:port-2 foo2 bar2', 321 )) 322 323 self.assertEqual(expected, result) 324 325 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 326 def test_creates_a_listen_stanza_string_server_options(self): 327 service_name = 'some-name' 328 service_ip = '10.11.12.13' 329 service_port = 1234 330 service_options = ('foo', 'bar') 331 server_entries = [ 332 ('name-1', 'ip-1', 'port-1', 'foo1 bar1'), 333 ('name-2', 'ip-2', 'port-2', 'foo2 bar2'), 334 ] 335 336 result = hooks.create_listen_stanza(service_name, service_ip, 337 service_port, service_options, 338 server_entries) 339 340 expected = '\n'.join(( 341 'frontend haproxy-2-1234', 342 ' bind 10.11.12.13:1234', 343 ' default_backend some-name', 344 '', 345 'backend some-name', 346 ' foo', 347 ' bar', 348 ' server name-1 ip-1:port-1 foo1 bar1', 349 ' server name-2 ip-2:port-2 foo2 bar2', 350 )) 351 352 self.assertEqual(expected, result) 353 354 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 355 def test_create_listen_stanza_filters_frontend_options(self): 356 service_name = 'some-name' 357 service_ip = '10.11.12.13' 358 service_port = 1234 359 service_options = ('capture request header X-Man', 'mode http', 360 'option httplog', 'retries 3', 'balance uri', 361 'option logasap') 362 server_entries = [ 363 ('name-1', 'ip-1', 'port-1', ('foo1', 'bar1')), 364 ('name-2', 'ip-2', 'port-2', ('foo2', 'bar2')), 365 ] 366 367 result = hooks.create_listen_stanza(service_name, service_ip, 368 service_port, service_options, 369 server_entries) 370 371 expected = '\n'.join(( 372 'frontend haproxy-2-1234', 373 ' bind 10.11.12.13:1234', 374 ' default_backend some-name', 375 ' mode http', 376 ' option httplog', 377 ' capture request header X-Man', 378 ' option logasap', 379 '', 380 'backend some-name', 381 ' mode http', 382 ' option httplog', 383 ' retries 3', 384 ' balance uri', 385 ' server name-1 ip-1:port-1 foo1 bar1', 386 ' server name-2 ip-2:port-2 foo2 bar2', 387 )) 388 389 self.assertEqual(expected, result) 390 391 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 392 def test_creates_a_listen_stanza_with_tuple_entries(self): 393 service_name = 'some-name' 394 service_ip = '10.11.12.13' 395 service_port = 1234 396 service_options = ('foo', 'bar') 397 server_entries = ( 398 ('name-1', 'ip-1', 'port-1', ('foo1', 'bar1')), 399 ('name-2', 'ip-2', 'port-2', ('foo2', 'bar2')), 400 ) 401 402 result = hooks.create_listen_stanza(service_name, service_ip, 403 service_port, service_options, 404 server_entries) 405 406 expected = '\n'.join(( 407 'frontend haproxy-2-1234', 408 ' bind 10.11.12.13:1234', 409 ' default_backend some-name', 410 '', 411 'backend some-name', 412 ' foo', 413 ' bar', 414 ' server name-1 ip-1:port-1 foo1 bar1', 415 ' server name-2 ip-2:port-2 foo2 bar2', 416 )) 417 418 self.assertEqual(expected, result) 419 420 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 421 def test_creates_a_listen_stanza_with_errorfiles(self): 422 service_name = 'some-name' 423 service_ip = '10.11.12.13' 424 service_port = 1234 425 service_options = ('foo', 'bar') 426 server_entries = [ 427 ('name-1', 'ip-1', 'port-1', ('foo1', 'bar1')), 428 ('name-2', 'ip-2', 'port-2', ('foo2', 'bar2')), 429 ] 430 content = ("HTTP/1.0 403 Forbidden\r\n" 431 "Content-Type: text/html\r\n" 432 "\r\n" 433 "<html></html>") 434 errorfiles = [{'http_status': 403, 435 'content': base64.b64encode(content)}] 436 437 result = hooks.create_listen_stanza(service_name, service_ip, 438 service_port, service_options, 439 server_entries, errorfiles) 440 441 expected = '\n'.join(( 442 'frontend haproxy-2-1234', 443 ' bind 10.11.12.13:1234', 444 ' default_backend some-name', 445 '', 446 'backend some-name', 447 ' foo', 448 ' bar', 449 ' errorfile 403 /var/lib/haproxy/service_some-name/403.http', 450 ' server name-1 ip-1:port-1 foo1 bar1', 451 ' server name-2 ip-2:port-2 foo2 bar2', 452 )) 453 454 self.assertEqual(expected, result) 455 456 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 457 def test_creates_a_listen_stanza_with_crts(self): 458 service_name = 'foo' 459 service_ip = '1.2.3.4' 460 service_port = 443 461 server_entries = [ 462 ('name-1', 'ip-1', 'port-1', ('foo1', 'bar1')), 463 ] 464 content = ("-----BEGIN CERTIFICATE-----\n" 465 "<data>\n" 466 "-----END CERTIFICATE-----\n") 467 crts = [base64.b64encode(content)] 468 469 result = hooks.create_listen_stanza(service_name, service_ip, 470 service_port, 471 server_entries=server_entries, 472 service_crts=crts) 473 474 crt_path = '/var/lib/haproxy/service_foo/0.pem' 475 expected = '\n'.join(( 476 'frontend haproxy-2-443', 477 ' bind 1.2.3.4:443 ssl crt %s no-sslv3' % crt_path, 478 ' default_backend foo', 479 '', 480 'backend foo', 481 ' server name-1 ip-1:port-1 foo1 bar1', 482 )) 483 484 self.assertEqual(expected, result) 485 486 @patch.dict(os.environ, {"JUJU_UNIT_NAME": "haproxy/2"}) 487 def test_creates_a_listen_stanza_with_backends(self): 488 service_name = 'foo' 489 service_ip = '1.2.3.4' 490 service_port = 80 491 server_entries = [ 492 ('name-1', 'ip-1', 'port-1', ('foo1', 'bar1')), 493 ] 494 service_backends = [ 495 {"backend_name": "foo-bar", 496 "servers": [ 497 ('bar-name-1', 'bar-ip-1', 'bar-port-1', ('bar2', 'bar3')) 498 ]} 499 ] 500 result = hooks.create_listen_stanza( 501 service_name, service_ip, service_port, 502 server_entries=server_entries, service_backends=service_backends) 503 504 expected = '\n'.join(( 505 'frontend haproxy-2-80', 506 ' bind 1.2.3.4:80', 507 ' default_backend foo', 508 '', 509 'backend foo', 510 ' server name-1 ip-1:port-1 foo1 bar1', 511 '', 512 'backend foo-bar', 513 ' server bar-name-1 bar-ip-1:bar-port-1 bar2 bar3', 514 )) 515 516 self.assertEqual(expected, result) 517 518 def test_doesnt_create_listen_stanza_if_args_not_provided(self): 519 self.assertIsNone(hooks.create_listen_stanza()) 520 521 @patch('hooks.create_listen_stanza') 522 @patch('hooks.config_get') 523 @patch('hooks.get_monitoring_password') 524 def test_creates_a_monitoring_stanza(self, get_monitoring_password, 525 config_get, create_listen_stanza): 526 config_get.return_value = { 527 'enable_monitoring': True, 528 'monitoring_allowed_cidr': 'some-cidr', 529 'monitoring_password': 'some-pass', 530 'monitoring_username': 'some-user', 531 'monitoring_stats_refresh': 123, 532 'monitoring_port': 1234, 533 } 534 create_listen_stanza.return_value = 'some result' 535 536 result = hooks.create_monitoring_stanza(service_name="some-service") 537 538 self.assertEqual('some result', result) 539 get_monitoring_password.assert_called_with() 540 create_listen_stanza.assert_called_with( 541 'some-service', '0.0.0.0', 1234, [ 542 'mode http', 543 'acl allowed_cidr src some-cidr', 544 'http-request deny unless allowed_cidr', 545 'stats enable', 546 'stats uri /', 547 'stats realm Haproxy\\ Statistics', 548 'stats auth some-user:some-pass', 549 'stats refresh 123', 550 ]) 551 552 @patch('hooks.create_listen_stanza') 553 @patch('hooks.config_get') 554 @patch('hooks.get_monitoring_password') 555 def test_doesnt_create_a_monitoring_stanza_if_monitoring_disabled( 556 self, get_monitoring_password, config_get, create_listen_stanza): 557 config_get.return_value = { 558 'enable_monitoring': False, 559 } 560 561 result = hooks.create_monitoring_stanza(service_name="some-service") 562 563 self.assertIsNone(result) 564 self.assertFalse(get_monitoring_password.called) 565 self.assertFalse(create_listen_stanza.called) 566 567 @patch('hooks.create_listen_stanza') 568 @patch('hooks.config_get') 569 @patch('hooks.get_monitoring_password') 570 def test_uses_monitoring_password_for_stanza(self, get_monitoring_password, 571 config_get, 572 create_listen_stanza): 573 config_get.return_value = { 574 'enable_monitoring': True, 575 'monitoring_allowed_cidr': 'some-cidr', 576 'monitoring_password': 'changeme', 577 'monitoring_username': 'some-user', 578 'monitoring_stats_refresh': 123, 579 'monitoring_port': 1234, 580 } 581 create_listen_stanza.return_value = 'some result' 582 get_monitoring_password.return_value = 'some-monitoring-pass' 583 584 hooks.create_monitoring_stanza(service_name="some-service") 585 586 get_monitoring_password.assert_called_with() 587 create_listen_stanza.assert_called_with( 588 'some-service', '0.0.0.0', 1234, [ 589 'mode http', 590 'acl allowed_cidr src some-cidr', 591 'http-request deny unless allowed_cidr', 592 'stats enable', 593 'stats uri /', 594 'stats realm Haproxy\\ Statistics', 595 'stats auth some-user:some-monitoring-pass', 596 'stats refresh 123', 597 ]) 598 599 @patch('hooks.pwgen') 600 @patch('hooks.create_listen_stanza') 601 @patch('hooks.config_get') 602 @patch('hooks.get_monitoring_password') 603 def test_uses_new_password_for_stanza(self, get_monitoring_password, 604 config_get, create_listen_stanza, 605 pwgen): 606 config_get.return_value = { 607 'enable_monitoring': True, 608 'monitoring_allowed_cidr': 'some-cidr', 609 'monitoring_password': 'changeme', 610 'monitoring_username': 'some-user', 611 'monitoring_stats_refresh': 123, 612 'monitoring_port': 1234, 613 } 614 create_listen_stanza.return_value = 'some result' 615 get_monitoring_password.return_value = None 616 pwgen.return_value = 'some-new-pass' 617 618 hooks.create_monitoring_stanza(service_name="some-service") 619 620 get_monitoring_password.assert_called_with() 621 create_listen_stanza.assert_called_with( 622 'some-service', '0.0.0.0', 1234, [ 623 'mode http', 624 'acl allowed_cidr src some-cidr', 625 'http-request deny unless allowed_cidr', 626 'stats enable', 627 'stats uri /', 628 'stats realm Haproxy\\ Statistics', 629 'stats auth some-user:some-new-pass', 630 'stats refresh 123', 631 ]) 632 633 @patch('hooks.is_proxy') 634 @patch('hooks.config_get') 635 @patch('yaml.safe_load') 636 def test_gets_config_services(self, safe_load, config_get, is_proxy): 637 config_get.return_value = { 638 'services': 'some-services', 639 } 640 safe_load.return_value = [ 641 { 642 'service_name': 'foo', 643 'service_options': { 644 'foo-1': 123, 645 }, 646 'service_options': ['foo1', 'foo2'], 647 'server_options': ['baz1', 'baz2'], 648 }, 649 { 650 'service_name': 'bar', 651 'service_options': ['bar1', 'bar2'], 652 'server_options': ['baz1', 'baz2'], 653 }, 654 ] 655 is_proxy.return_value = False 656 657 result = hooks.get_config_services() 658 expected = { 659 None: { 660 'service_name': 'foo', 661 }, 662 'foo': { 663 'service_name': 'foo', 664 'service_options': ['foo1', 'foo2'], 665 'server_options': ['baz1', 'baz2'], 666 }, 667 'bar': { 668 'service_name': 'bar', 669 'service_options': ['bar1', 'bar2'], 670 'server_options': ['baz1', 'baz2'], 671 }, 672 } 673 674 self.assertEqual(expected, result) 675 676 @patch('hooks.is_proxy') 677 @patch('hooks.config_get') 678 @patch('yaml.safe_load') 679 def test_gets_config_services_with_forward_option(self, safe_load, 680 config_get, is_proxy): 681 config_get.return_value = { 682 'services': 'some-services', 683 } 684 safe_load.return_value = [ 685 { 686 'service_name': 'foo', 687 'service_options': { 688 'foo-1': 123, 689 }, 690 'service_options': ['foo1', 'foo2'], 691 'server_options': ['baz1', 'baz2'], 692 }, 693 { 694 'service_name': 'bar', 695 'service_options': ['bar1', 'bar2'], 696 'server_options': ['baz1', 'baz2'], 697 }, 698 ] 699 is_proxy.return_value = True 700 701 result = hooks.get_config_services() 702 expected = { 703 None: { 704 'service_name': 'foo', 705 }, 706 'foo': { 707 'service_name': 'foo', 708 'service_options': ['foo1', 'foo2', 'option forwardfor'], 709 'server_options': ['baz1', 'baz2'], 710 }, 711 'bar': { 712 'service_name': 'bar', 713 'service_options': ['bar1', 'bar2', 'option forwardfor'], 714 'server_options': ['baz1', 'baz2'], 715 }, 716 } 717 718 self.assertEqual(expected, result) 719 720 @patch('hooks.is_proxy') 721 @patch('hooks.config_get') 722 @patch('yaml.safe_load') 723 def test_gets_config_services_with_options_string(self, safe_load, 724 config_get, is_proxy): 725 config_get.return_value = { 726 'services': 'some-services', 727 } 728 safe_load.return_value = [ 729 { 730 'service_name': 'foo', 731 'service_options': { 732 'foo-1': 123, 733 }, 734 'service_options': ['foo1', 'foo2'], 735 'server_options': 'baz1, baz2', 736 }, 737 { 738 'service_name': 'bar', 739 'service_options': ['bar1', 'bar2'], 740 'server_options': 'baz1, baz2', 741 }, 742 ] 743 is_proxy.return_value = False 744 745 result = hooks.get_config_services() 746 expected = { 747 None: { 748 'service_name': 'foo', 749 }, 750 'foo': { 751 'service_name': 'foo', 752 'service_options': ['foo1', 'foo2'], 753 'server_options': ['baz1', 'baz2'], 754 }, 755 'bar': { 756 'service_name': 'bar', 757 'service_options': ['bar1', 'bar2'], 758 'server_options': ['baz1', 'baz2'], 759 }, 760 } 761 762 self.assertEqual(expected, result) 763 764 @patch('hooks.is_proxy') 765 @patch('hooks.config_get') 766 @patch('yaml.safe_load') 767 def test_gets_config_services_with_proxy_no_forward(self, safe_load, 768 config_get, is_proxy): 769 config_get.return_value = { 770 'services': 'some-services', 771 } 772 safe_load.return_value = [ 773 { 774 'service_name': 'foo', 775 'service_options': { 776 'foo-1': 123, 777 }, 778 'service_options': ['foo1', 'foo2'], 779 'server_options': 'baz1, baz2', 780 }, 781 { 782 'service_name': 'bar', 783 'service_options': ['bar1', 'bar2'], 784 'server_options': 'baz1, baz2', 785 }, 786 ] 787 is_proxy.return_value = True 788 789 result = hooks.get_config_services() 790 expected = { 791 None: { 792 'service_name': 'foo', 793 }, 794 'foo': { 795 'service_name': 'foo', 796 'service_options': ['foo1', 'foo2', 'option forwardfor'], 797 'server_options': ['baz1', 'baz2'], 798 }, 799 'bar': { 800 'service_name': 'bar', 801 'service_options': ['bar1', 'bar2', 'option forwardfor'], 802 'server_options': ['baz1', 'baz2'], 803 }, 804 } 805 806 self.assertEqual(expected, result) 807 808 @patch('hooks.is_proxy') 809 @patch('hooks.config_get') 810 @patch('yaml.safe_load') 811 def test_gets_config_services_no_service_options(self, safe_load, 812 config_get, is_proxy): 813 config_get.return_value = { 814 'services': '', 815 } 816 safe_load.return_value = [ 817 { 818 'service_name': 'foo', 819 'server_options': 'baz1, baz2', 820 }, 821 { 822 'service_name': 'bar', 823 'server_options': 'baz1, baz2', 824 }, 825 ] 826 is_proxy.return_value = True 827 828 result = hooks.get_config_services() 829 expected = { 830 None: { 831 'service_name': 'foo', 832 }, 833 'foo': { 834 'service_name': 'foo', 835 'server_options': ['baz1', 'baz2'], 836 }, 837 'bar': { 838 'service_name': 'bar', 839 'server_options': ['baz1', 'baz2'], 840 }, 841 } 842 843 self.assertEqual(expected, result) 844 845 @patch('hooks.get_config_services') 846 def test_gets_a_service_config(self, get_config_services): 847 get_config_services.return_value = { 848 'foo': 'bar', 849 } 850 851 self.assertEqual('bar', hooks.get_config_service('foo')) 852 853 @patch('hooks.get_config_services') 854 def test_gets_a_service_config_from_none(self, get_config_services): 855 get_config_services.return_value = { 856 None: 'bar', 857 } 858 859 self.assertEqual('bar', hooks.get_config_service()) 860 861 @patch('hooks.get_config_services') 862 def test_gets_a_service_config_as_none(self, get_config_services): 863 get_config_services.return_value = { 864 'baz': 'bar', 865 } 866 867 self.assertIsNone(hooks.get_config_service()) 868 869 @patch('os.path.exists') 870 def test_mark_as_proxy_when_path_exists(self, path_exists): 871 path_exists.return_value = True 872 873 self.assertTrue(hooks.is_proxy('foo')) 874 path_exists.assert_called_with('/var/run/haproxy/foo.is.proxy') 875 876 @patch('os.path.exists') 877 def test_doesnt_mark_as_proxy_when_path_doesnt_exist(self, path_exists): 878 path_exists.return_value = False 879 880 self.assertFalse(hooks.is_proxy('foo')) 881 path_exists.assert_called_with('/var/run/haproxy/foo.is.proxy') 882 883 @patch('os.path.exists') 884 def test_loads_services_by_name(self, path_exists): 885 with patch_open() as (mock_open, mock_file): 886 path_exists.return_value = True 887 mock_file.read.return_value = 'some content' 888 889 result = hooks.load_services('some-service') 890 891 self.assertEqual('some content', result) 892 mock_open.assert_called_with( 893 '/var/run/haproxy/some-service.service') 894 mock_file.read.assert_called_with() 895 896 @patch('os.path.exists') 897 def test_loads_no_service_if_path_doesnt_exist(self, path_exists): 898 path_exists.return_value = False 899 900 result = hooks.load_services('some-service') 901 902 self.assertIsNone(result) 903 904 @patch('glob.glob') 905 def test_loads_services_within_dir_if_no_name_provided(self, glob): 906 with patch_open() as (mock_open, mock_file): 907 mock_file.read.side_effect = ['foo', 'bar'] 908 glob.return_value = ['foo-file', 'bar-file'] 909 910 result = hooks.load_services() 911 912 self.assertEqual('foo\n\nbar\n\n', result) 913 mock_open.assert_has_calls([call('foo-file'), call('bar-file')]) 914 mock_file.read.assert_has_calls([call(), call()]) 915 916 @patch('hooks.os') 917 def test_removes_services_by_name(self, os_): 918 service_path = '/var/run/haproxy/some-service.service' 919 os_.path.exists.return_value = True 920 921 self.assertTrue(hooks.remove_services('some-service')) 922 923 os_.path.exists.assert_called_with(service_path) 924 os_.remove.assert_called_with(service_path) 925 926 @patch('hooks.os') 927 def test_removes_nothing_if_service_doesnt_exist(self, os_): 928 service_path = '/var/run/haproxy/some-service.service' 929 os_.path.exists.return_value = False 930 931 self.assertTrue(hooks.remove_services('some-service')) 932 933 os_.path.exists.assert_called_with(service_path) 934 935 @patch('hooks.os') 936 @patch('glob.glob') 937 def test_removes_all_services_in_dir_if_name_not_provided(self, glob, os_): 938 glob.return_value = ['foo', 'bar'] 939 940 self.assertTrue(hooks.remove_services()) 941 942 os_.remove.assert_has_calls([call('foo'), call('bar')]) 943 944 @patch('hooks.os') 945 @patch('hooks.log') 946 def test_logs_error_when_failing_to_remove_service_by_name(self, log, os_): 947 error = Exception('some error') 948 os_.path.exists.return_value = True 949 os_.remove.side_effect = error 950 951 self.assertFalse(hooks.remove_services('some-service')) 952 953 log.assert_called_with(str(error)) 954 955 @patch('hooks.os') 956 @patch('hooks.log') 957 @patch('glob.glob') 958 def test_logs_error_when_failing_to_remove_services(self, glob, log, os_): 959 errors = [Exception('some error 1'), Exception('some error 2')] 960 os_.remove.side_effect = errors 961 glob.return_value = ['foo', 'bar'] 962 963 self.assertTrue(hooks.remove_services()) 964 965 log.assert_has_calls([ 966 call(str(errors[0])), 967 call(str(errors[1])), 968 ]) 969 970 @patch('subprocess.call') 971 def test_calls_check_action(self, mock_call): 972 mock_call.return_value = 0 973 974 result = hooks.service_haproxy('check') 975 976 self.assertTrue(result) 977 mock_call.assert_called_with(['/usr/sbin/haproxy', '-f', 978 hooks.default_haproxy_config, '-c']) 979 980 @patch('subprocess.call') 981 def test_calls_check_action_with_different_config(self, mock_call): 982 mock_call.return_value = 0 983 984 result = hooks.service_haproxy('check', 'some-config') 985 986 self.assertTrue(result) 987 mock_call.assert_called_with(['/usr/sbin/haproxy', '-f', 988 'some-config', '-c']) 989 990 @patch('subprocess.call') 991 def test_fails_to_check_config(self, mock_call): 992 mock_call.return_value = 1 993 994 result = hooks.service_haproxy('check') 995 996 self.assertFalse(result) 997 998 @patch('subprocess.call') 999 def test_calls_different_actions(self, mock_call): 1000 mock_call.return_value = 0 1001 1002 result = hooks.service_haproxy('foo') 1003 1004 self.assertTrue(result) 1005 mock_call.assert_called_with(['service', 'haproxy', 'foo']) 1006 1007 @patch('subprocess.call') 1008 def test_fails_to_call_different_actions(self, mock_call): 1009 mock_call.return_value = 1 1010 1011 result = hooks.service_haproxy('foo') 1012 1013 self.assertFalse(result) 1014 1015 @patch('subprocess.call') 1016 def test_doesnt_call_actions_if_action_not_provided(self, mock_call): 1017 self.assertIsNone(hooks.service_haproxy()) 1018 self.assertFalse(mock_call.called) 1019 1020 @patch('subprocess.call') 1021 def test_doesnt_call_actions_if_config_is_none(self, mock_call): 1022 self.assertIsNone(hooks.service_haproxy('foo', None)) 1023 self.assertFalse(mock_call.called)