Rush has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/403202 )
Change subject: wip: rabbitmq: handling users and initial setup ...................................................................... wip: rabbitmq: handling users and initial setup A few inconsistencies and issues across our stuff: * labtestcontrol2001 did not have the management plugin enabled which made the cleanup cron invalid * the queuecleanup script did not handle a queue not being present yet and they are created dynamically (this is not by necessarily an errant state) * queuecleanup script had hard coded credentials * There has been no way to manage rabbitmq users and this has largely been done adhoc and outside of Puppets purview resulting in inconsistencies * Rabbitmq can run on the non-primary control node and really needs to in order to manage rabbit internals as rabbit has a local user database and settings. * guest account had been left in use on installs * header docs for rabbit/init.pp were confusing Change-Id: I1870faa07e49603bd7eff9f38cc1202519aeb467 --- M modules/profile/manifests/openstack/base/rabbitmq.pp M modules/rabbitmq/files/drain_queue A modules/rabbitmq/files/rabbit_random_guest.sh M modules/rabbitmq/manifests/cleanup.pp M modules/rabbitmq/manifests/init.pp A modules/rabbitmq/manifests/user.pp 6 files changed, 142 insertions(+), 27 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/operations/puppet refs/changes/02/403202/1 diff --git a/modules/profile/manifests/openstack/base/rabbitmq.pp b/modules/profile/manifests/openstack/base/rabbitmq.pp index efd0127..ffececf 100644 --- a/modules/profile/manifests/openstack/base/rabbitmq.pp +++ b/modules/profile/manifests/openstack/base/rabbitmq.pp @@ -10,7 +10,6 @@ ){ class { '::rabbitmq': - running => $::fqdn == $nova_controller, file_handles => $file_handles, } contain '::rabbitmq' diff --git a/modules/rabbitmq/files/drain_queue b/modules/rabbitmq/files/drain_queue index bd14e4e..4b98dbf 100644 --- a/modules/rabbitmq/files/drain_queue +++ b/modules/rabbitmq/files/drain_queue @@ -28,17 +28,21 @@ import urllib.parse +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + def die(s): - print('*** {}'.format(s), file=sys.stderr) + eprint('*** {}'.format(s)) exit(1) - -def http_req(verb, path, body=None): +def http_req(username, password, verb, path, body=None): path = '/api%s' % path conn = http.client.HTTPConnection('localhost', 15672) + credentials = '{}:{}'.format(username, password) + b = credentials.encode() headers = { 'Authorization': 'Basic {}'.format( - base64.b64encode(b'guest:guest').decode('ascii')), + base64.b64encode(b).decode('ascii')), } if body: headers['Content-Type'] = 'application/json' @@ -53,11 +57,20 @@ if resp.status == 401: die('Access refused: {}'.format(path)) if resp.status == 404: - die('Not found: {}'.format(path)) + # Rabbitmq manages queues dynamically so + # the existence of a queue may depend on a message + # ever needing to be delivered to it. Even + # necessary queues are often created on-demand. + eprint('Queue not found!') + return json.dumps('') if resp.status == 301: url = urllib.parse.urlparse(resp.getheader('location')) [host, port] = url.netloc.split(':') - return http_req(verb, url.path + '?' + url.query, body) + return http_req(username, + password, + verb, + url.path + '?' + url.query, + body) if resp.status < 200 or resp.status > 400: raise Exception( 'Received {:d} {} for path {}\n{}'.format( @@ -65,12 +78,19 @@ return resp_body -def http_json(verb, path, body=None): - return json.loads(http_req(verb, path, body)) +def http_json(username, password, verb, path, body=None): + return json.loads(http_req(username, password, verb, path, body)) -def message_count(queue): - return http_json('GET', '/queues/%2F/{}'.format(queue))['messages_ready'] +def message_count(username, password, queue): + out = http_json(username, + password, + 'GET', + '/queues/%2F/{}'.format(queue)) + if not out: + return None + return out['messages_ready'] + def main(): @@ -86,14 +106,29 @@ parser.add_argument( 'queue', metavar='QUEUE', nargs=1, help='queue to read messages from') + parser.add_argument( + '--username', default='drainqueue', + help='username to connect to rabbitmq') + parser.add_argument( + '--password', default='', + help='password to connect to rabbitmq') + args = parser.parse_args() queue = args.queue[0] + username = args.username + password = args.password if args.silent: - http_req('DELETE', '/queues/%2F/{}/contents'.format(queue)) + http_req(username, + password, + 'DELETE', + '/queues/%2F/{}/contents'.format(queue)) else: - ready = message_count(queue) + ready = message_count(username, password, queue) + if ready is None: + return + print("message count is {}".format(ready)) while ready > 0: msgs = http_json( 'POST', @@ -113,7 +148,7 @@ if args.requeue: ready = 0 # prevent infinte loops else: - ready = message_count(queue) + ready = message_count(username, password, queue) if __name__ == '__main__': diff --git a/modules/rabbitmq/files/rabbit_random_guest.sh b/modules/rabbitmq/files/rabbit_random_guest.sh new file mode 100644 index 0000000..40527ca --- /dev/null +++ b/modules/rabbitmq/files/rabbit_random_guest.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# A guest user with a default 'guest' password will +# automatically be created for the RabbitMQ service. +# It should be never used + +# recommendations seems to be to set to unknown +# value rather than remove the default account +# which may be handwaving based on older versions +# of rabbitmq not handling the missing builtin well +RNDM=$(date +%s | sha256sum | base64 | head -c 32 ; echo) +/usr/sbin/rabbitmqctl change_password guest $RNDM +/usr/sbin/rabbitmqctl list_users diff --git a/modules/rabbitmq/manifests/cleanup.pp b/modules/rabbitmq/manifests/cleanup.pp index ac2afa0..bd5b44c 100644 --- a/modules/rabbitmq/manifests/cleanup.pp +++ b/modules/rabbitmq/manifests/cleanup.pp @@ -2,11 +2,20 @@ # that are not being consumed and this becomes costly # over time. +# Enabled is only for active cron, all other +# components are setup if the class is included. + class rabbitmq::cleanup( $enabled=false, + $username='drainqueue', + $password, ) { require rabbitmq + + if ! ($password) { + fail("password must be set for ${name}") + } if ($enabled) { $ensure = 'present' @@ -15,11 +24,24 @@ $ensure = 'absent' } + file { '/usr/local/sbin/drain_queue': + ensure => 'present', + owner => 'root', + group => 'root', + mode => '0655', + source => 'puppet:///modules/rabbitmq/drain_queue', + } + + rabbitmq::user{'drainqueue': + username => $username, + password => $password, + } + # These logfiles will be rotated by an already-existing wildcard logrotate rule for rabbit cron { 'drain and log rabbit notifications.error queue': ensure => $ensure, user => 'root', minute => '35', - command => '/usr/local/sbin/drain_queue notifications.error >> /var/log/rabbitmq/notifications_error.log 2>&1', + command => "/usr/local/sbin/drain_queue notifications.error --password ${password}>> /var/log/rabbitmq/notifications_error.log 2>&1", } } diff --git a/modules/rabbitmq/manifests/init.pp b/modules/rabbitmq/manifests/init.pp index 3e905ff..16dadb0 100644 --- a/modules/rabbitmq/manifests/init.pp +++ b/modules/rabbitmq/manifests/init.pp @@ -2,22 +2,21 @@ # # User MAC's are not handled by Puppet # -# Changing a user password -# rabbitmqctl change_password <user> <password> # Adding a user # rabbitmqctl add_user <user> <password> -# -# Creating user "<user>" ... +# Changing a user password # rabbitmqctl change_password <user> <password> -# rabbitmqctl set_user_tags <user> administrator +# # Setting tags for user "<user>" to [administrator] ... +# rabbitmqctl set_user_tags <user> administrator +# All permissions example # rabbitmqctl set_permissions -p / <user> ".*" ".*" ".*" # # The management plugin may be desired # rabbitmq-plugins enable rabbitmq_management class rabbitmq( - $running = false, + $running = true, $file_handles = '1024', ) { @@ -53,12 +52,31 @@ require => Package['rabbitmq-server'], } - file { '/usr/local/sbin/drain_queue': - ensure => 'present', - owner => 'root', - group => 'root', - mode => '0655', - source => 'puppet:///modules/rabbitmq/drain_queue', + file {'/usr/local/sbin/rabbit_random_guest': + ensure => 'present', + owner => 'root', + group => 'root', + mode => '0655', + source => 'puppet:///modules/rabbitmq/random_guesh.sh', + require => Package['rabbitmq-server'], + } + + exec { 'invalidate_rabbitmq_guest_account': + command => 'rabbit_random_guest' + path => ['/usr/local/sbin/'], + subscribe => File['/usr/local/sbin/random_guest'], + refreshonly => true, + } + + # this appears to be idempotent + # https://www.rabbitmq.com/management.html + # Needed for https://www.rabbitmq.com/management-cli.html + # rabbitmq-plugins -E list | egrep '\[E\*]\srabbitmq_management + exec { 'enable_management_plugin': + command => 'rabbitmq-plugins enable rabbitmq_management' + path => ['/usr/sbin/'], + subscribe => Package['rabbitmq-server'], + refreshonly => true, } service { 'rabbitmq-server': diff --git a/modules/rabbitmq/manifests/user.pp b/modules/rabbitmq/manifests/user.pp new file mode 100644 index 0000000..5eb2e43 --- /dev/null +++ b/modules/rabbitmq/manifests/user.pp @@ -0,0 +1,29 @@ +class rabbitmq::user( + $ensure='present', + $username, + $password, + $permissions='".*" ".*" ".*"', + ), { + + if ($ensure == 'present') { + exec {'rabbit_user_create': + command => "rabbitmqctl add_user ${user} ${password}", + path => ['/usr/sbin/'], + unless => "rabbitmqctl list_users | grep --quiet ${USER}", + notify => Exec['rabbit_user_setup_perms'], + } + + exec {'rabbit_user_setup_perms': + command => "rabbitmqctl set_permissions ${permissions}", + path => ['/usr/sbin/'], + refreshonly => true, + } + } + + if ($ensure == 'absent') { + exec {'rabbit_user_removal': + command => "rabbitmqctl delete_user ${user}", + onlyif => "rabbitmqctl list_users | grep --quiet ${USER}", + } + } +} -- To view, visit https://gerrit.wikimedia.org/r/403202 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1870faa07e49603bd7eff9f38cc1202519aeb467 Gerrit-PatchSet: 1 Gerrit-Project: operations/puppet Gerrit-Branch: production Gerrit-Owner: Rush <r...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits