Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Postgres ssl mode prefer #21498

Merged
merged 10 commits into from
Feb 16, 2017
67 changes: 67 additions & 0 deletions lib/ansible/module_utils/postgres.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Copyright (c), Ted Timmons <ted@timmons.me>, 2017.
# Most of this was originally added by other creators in the postgresql_user module.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# standard ansible imports
from ansible.module_utils.basic import get_exception

# standard PG imports
HAS_PSYCOPG2 = False
try:
import psycopg2
import psycopg2.extras
except ImportError:
pass
else:
HAS_PSYCOPG2 = True

from ansible.module_utils.six import iteritems

class LibraryError(Exception):
pass

def ensure_libs(sslrootcert=None):
if not HAS_PSYCOPG2:
raise LibraryError('psycopg2 is not installed. we need psycopg2.')
if sslrootcert and psycopg2.__version__ < '2.4.3':
raise LibraryError('psycopg2 must be at least 2.4.3 in order to use the ssl_rootcert parameter')

# no problems
return None

def postgres_common_argument_spec():
return dict(
login_user = dict(default='postgres'),
login_password = dict(default='', no_log=True),
login_host = dict(default=''),
login_unix_socket = dict(default=''),
port = dict(type='int', default=5432),
ssl_mode = dict(default='prefer', choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
ssl_rootcert = dict(default=None),
)

120 changes: 38 additions & 82 deletions lib/ansible/modules/database/postgresql/postgresql_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,11 @@
- name of the database to add or remove
required: true
default: null
login_user:
description:
- The username used to authenticate with
required: false
default: null
login_password:
description:
- The password used to authenticate with
required: false
default: null
login_host:
description:
- Host running the database
required: false
default: localhost
login_unix_socket:
description:
- Path to a Unix domain socket for local connections
required: false
default: null
owner:
description:
- Name of the role to set as owner of the database
required: false
default: null
port:
description:
- Database port to connect to.
required: false
default: 5432
template:
description:
- Template used to create the database
Expand All @@ -89,27 +64,9 @@
required: false
default: present
choices: [ "present", "absent" ]
ssl_mode:
description:
- Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server.
- See https://www.postgresql.org/docs/current/static/libpq-ssl.html for more information on the modes.
required: false
default: disable
choices: [disable, allow, prefer, require, verify-ca, verify-full]
version_added: '2.3'
ssl_rootcert:
description:
- Specifies the name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities.
required: false
default: null
version_added: '2.3'
notes:
- The default authentication assumes that you are either logging in as or sudo'ing to the C(postgres) account on the host.
- This module uses I(psycopg2), a Python PostgreSQL database adapter. You must ensure that psycopg2 is installed on
the host before using this module. If the remote host is the PostgreSQL server (which is the default case), then PostgreSQL must also be installed on the remote host. For Ubuntu-based systems, install the C(postgresql), C(libpq-dev), and C(python-psycopg2) packages on the remote host before using this module.
- The ssl_rootcert parameter requires at least Postgres version 8.4 and I(psycopg2) version 2.4.3.
requirements: [ psycopg2 ]
author: "Ansible Core Team"
extends_documentation_fragment:
- postgres
'''

EXAMPLES = '''
Expand All @@ -128,15 +85,23 @@
template: template0
'''

HAS_PSYCOPG2 = False
try:
import psycopg2
import psycopg2.extras
except ImportError:
postgresqldb_found = False
pass
else:
postgresqldb_found = True
HAS_PSYCOPG2 = True
from ansible.module_utils.six import iteritems

import traceback

import ansible.module_utils.postgres as pgutils
from ansible.module_utils.database import SQLParseError, pg_quote_identifier
from ansible.module_utils.basic import get_exception, AnsibleModule


class NotSupportedError(Exception):
pass

Expand Down Expand Up @@ -243,27 +208,24 @@ def db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype):
#

def main():
argument_spec = pgutils.postgres_common_argument_spec()
argument_spec.update(dict(
db=dict(required=True, aliases=['name']),
owner=dict(default=""),
template=dict(default=""),
encoding=dict(default=""),
lc_collate=dict(default=""),
lc_ctype=dict(default=""),
state=dict(default="present", choices=["absent", "present"]),
))


module = AnsibleModule(
argument_spec=dict(
login_user=dict(default="postgres"),
login_password=dict(default="", no_log=True),
login_host=dict(default=""),
login_unix_socket=dict(default=""),
port=dict(default="5432"),
db=dict(required=True, aliases=['name']),
owner=dict(default=""),
template=dict(default=""),
encoding=dict(default=""),
lc_collate=dict(default=""),
lc_ctype=dict(default=""),
state=dict(default="present", choices=["absent", "present"]),
ssl_mode=dict(default="disable", choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
ssl_rootcert=dict(default=None),
),
argument_spec=argument_spec,
supports_check_mode = True
)

if not postgresqldb_found:
if not HAS_PSYCOPG2:
module.fail_json(msg="the python psycopg2 module is required")

db = module.params["db"]
Expand Down Expand Up @@ -296,38 +258,36 @@ def main():
if is_localhost and module.params["login_unix_socket"] != "":
kw["host"] = module.params["login_unix_socket"]

if psycopg2.__version__ < '2.4.3' and sslrootcert is not None:
module.fail_json(msg='psycopg2 must be at least 2.4.3 in order to user the ssl_rootcert parameter')

try:
pgutils.ensure_libs(sslrootcert=module.params.get('ssl_rootcert'))
db_connection = psycopg2.connect(database="postgres", **kw)
# Enable autocommit so we can create databases
if psycopg2.__version__ >= '2.4.2':
db_connection.autocommit = True
else:
db_connection.set_isolation_level(psycopg2
.extensions
.ISOLATION_LEVEL_AUTOCOMMIT)
cursor = db_connection.cursor(
cursor_factory=psycopg2.extras.DictCursor)
db_connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
cursor = db_connection.cursor(cursor_factory=psycopg2.extras.DictCursor)

except pgutils.LibraryError:
e = get_exception()
module.fail_json(msg="unable to connect to database: {0}".format(str(e)), exception=traceback.format_exc())

except TypeError:
e = get_exception()
if 'sslrootcert' in e.args[0]:
module.fail_json(msg='Postgresql server must be at least version 8.4 to support sslrootcert')
module.fail_json(msg="unable to connect to database: %s" % e)
module.fail_json(msg='Postgresql server must be at least version 8.4 to support sslrootcert. Exception: {0}'.format(e), exception=traceback.format_exc())
module.fail_json(msg="unable to connect to database: %s" % e, exception=traceback.format_exc())

except Exception:
e = get_exception()
module.fail_json(msg="unable to connect to database: %s" % e)
module.fail_json(msg="unable to connect to database: %s" % e, exception=traceback.format_exc())

try:
if module.check_mode:
if state == "absent":
changed = db_exists(cursor, db)
elif state == "present":
changed = not db_matches(cursor, db, owner, template, encoding,
lc_collate, lc_ctype)
changed = not db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype)
module.exit_json(changed=changed, db=db)

if state == "absent":
Expand All @@ -339,8 +299,7 @@ def main():

elif state == "present":
try:
changed = db_create(cursor, db, owner, template, encoding,
lc_collate, lc_ctype)
changed = db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype)
except SQLParseError:
e = get_exception()
module.fail_json(msg=str(e))
Expand All @@ -356,8 +315,5 @@ def main():

module.exit_json(changed=changed, db=db)

# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.database import *
if __name__ == '__main__':
main()
5 changes: 3 additions & 2 deletions lib/ansible/modules/database/postgresql/postgresql_privs.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@
description:
- Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server.
- See https://www.postgresql.org/docs/current/static/libpq-ssl.html for more information on the modes.
- Default of C(prefer) matches libpq default.
required: false
default: disable
default: prefer
choices: [disable, allow, prefer, require, verify-ca, verify-full]
version_added: '2.3'
ssl_rootcert:
Expand Down Expand Up @@ -571,7 +572,7 @@ def main():
unix_socket=dict(default='', aliases=['login_unix_socket']),
login=dict(default='postgres', aliases=['login_user']),
password=dict(default='', aliases=['login_password'], no_log=True),
ssl_mode=dict(default="disable", choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
ssl_mode=dict(default="prefer", choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
ssl_rootcert=dict(default=None)
),
supports_check_mode = True
Expand Down
5 changes: 3 additions & 2 deletions lib/ansible/modules/database/postgresql/postgresql_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@
description:
- Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server.
- See https://www.postgresql.org/docs/current/static/libpq-ssl.html for more information on the modes.
- Default of C(prefer) matches libpq default.
required: false
default: disable
default: prefer
choices: [disable, allow, prefer, require, verify-ca, verify-full]
version_added: '2.3'
ssl_rootcert:
Expand Down Expand Up @@ -596,7 +597,7 @@ def main():
encrypted=dict(type='bool', default='no'),
no_password_changes=dict(type='bool', default='no'),
expires=dict(default=None),
ssl_mode=dict(default='disable', choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
ssl_mode=dict(default='prefer', choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
ssl_rootcert=dict(default=None)
),
supports_check_mode = True
Expand Down
70 changes: 70 additions & 0 deletions lib/ansible/utils/module_docs_fragments/postgres.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.


class ModuleDocFragment(object):
# Postgres documentation fragment
DOCUMENTATION = """
options:
login_user:
description:
- The username used to authenticate with
required: false
default: postgres
login_password:
description:
- The password used to authenticate with
required: false
default: null
login_host:
description:
- Host running the database
required: false
default: null
login_unix_socket:
description:
- Path to a Unix domain socket for local connections
required: false
default: null
port:
description:
- Database port to connect to.
required: false
default: 5432
ssl_mode:
description:
- Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server.
- See https://www.postgresql.org/docs/current/static/libpq-ssl.html for more information on the modes.
- Default of C(prefer) matches libpq default.
required: false
default: prefer
choices: [disable, allow, prefer, require, verify-ca, verify-full]
version_added: '2.3'
ssl_rootcert:
description:
- Specifies the name of a file containing SSL certificate authority (CA) certificate(s).
- If the file exists, the server's certificate will be verified to be signed by one of these authorities.
required: false
default: null
version_added: '2.3'
notes:
- The default authentication assumes that you are either logging in as or sudo'ing to the C(postgres) account on the host.
- This module uses I(psycopg2), a Python PostgreSQL database adapter. You must ensure that psycopg2 is installed on
the host before using this module. If the remote host is the PostgreSQL server (which is the default case), then
PostgreSQL must also be installed on the remote host. For Ubuntu-based systems, install the C(postgresql), C(libpq-dev),
and C(python-psycopg2) packages on the remote host before using this module.
- The ssl_rootcert parameter requires at least Postgres version 8.4 and I(psycopg2) version 2.4.3.
requirements: [ psycopg2 ]
"""