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)