Improve CI (#281)
* Install PyOpenSSL and cryptography from PyPi if target Python != system Python. * Work around some CentOS6, 7, Ubuntu 16.04 problems. Improve jinja2 compatibility handling. * Skip tasks that require properties that aren't always there. * Only install OpenSSL when not present. * Improve output. * Improve get_certificate integration test graceful failing. * Fix tests. * Fix assert. * OpenSSL peculiarities. * Fix condition.pull/267/head
parent
63f4598737
commit
6c018b94da
|
@ -2,8 +2,8 @@
|
||||||
- name: Generate account keys
|
- name: Generate account keys
|
||||||
openssl_privatekey:
|
openssl_privatekey:
|
||||||
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
|
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
|
||||||
passphrase: "{{ item.pass | default(omit, true) }}"
|
passphrase: "{{ item.pass | default(omit) | default(omit, true) }}"
|
||||||
cipher: "{{ 'auto' if item.pass | default() else omit }}"
|
cipher: "{{ 'auto' if (item.pass | default(false)) else omit }}"
|
||||||
type: ECC
|
type: ECC
|
||||||
curve: secp256r1
|
curve: secp256r1
|
||||||
force: true
|
force: true
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
- name: Parse account keys (to ease debugging some test failures)
|
- name: Parse account keys (to ease debugging some test failures)
|
||||||
openssl_privatekey_info:
|
openssl_privatekey_info:
|
||||||
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
|
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
|
||||||
passphrase: "{{ item.pass | default(omit, true) }}"
|
passphrase: "{{ item.pass | default(omit) | default(omit, true) }}"
|
||||||
return_private_key_data: true
|
return_private_key_data: true
|
||||||
loop: "{{ account_keys }}"
|
loop: "{{ account_keys }}"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
- setup_acme
|
- setup_acme
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -264,92 +264,98 @@
|
||||||
set_fact:
|
set_fact:
|
||||||
cert_5_recreate_3: "{{ challenge_data is changed }}"
|
cert_5_recreate_3: "{{ challenge_data is changed }}"
|
||||||
cert_5d_obtain_results: "{{ certificate_obtain_result }}"
|
cert_5d_obtain_results: "{{ certificate_obtain_result }}"
|
||||||
- name: Obtain cert 6
|
- block:
|
||||||
include_tasks: obtain-cert.yml
|
- name: Obtain cert 6
|
||||||
vars:
|
include_tasks: obtain-cert.yml
|
||||||
certgen_title: Certificate 6
|
vars:
|
||||||
certificate_name: cert-6
|
certgen_title: Certificate 6
|
||||||
key_type: rsa
|
certificate_name: cert-6
|
||||||
rsa_bits: "{{ default_rsa_key_size }}"
|
key_type: rsa
|
||||||
subject_alt_name: "DNS:example.org"
|
rsa_bits: "{{ default_rsa_key_size }}"
|
||||||
subject_alt_name_critical: no
|
subject_alt_name: "DNS:example.org"
|
||||||
account_key: account-ec256
|
subject_alt_name_critical: no
|
||||||
challenge: tls-alpn-01
|
account_key: account-ec256
|
||||||
modify_account: yes
|
challenge: tls-alpn-01
|
||||||
deactivate_authzs: no
|
modify_account: yes
|
||||||
force: no
|
deactivate_authzs: no
|
||||||
remaining_days: 10
|
force: no
|
||||||
terms_agreed: yes
|
remaining_days: 10
|
||||||
account_email: "example@example.org"
|
terms_agreed: yes
|
||||||
acme_expected_root_number: 0
|
account_email: "example@example.org"
|
||||||
select_chain:
|
acme_expected_root_number: 0
|
||||||
# All intermediates have the same subject key identifier, so always
|
select_chain:
|
||||||
# the first chain will be found, and we need a second condition to
|
# All intermediates have the same subject key identifier, so always
|
||||||
# make sure that the first condition actually works. (The second
|
# the first chain will be found, and we need a second condition to
|
||||||
# condition has been tested above.)
|
# make sure that the first condition actually works. (The second
|
||||||
- test_certificates: first
|
# condition has been tested above.)
|
||||||
subject_key_identifier: "{{ acme_intermediates[0].subject_key_identifier }}"
|
- test_certificates: first
|
||||||
- test_certificates: last
|
subject_key_identifier: "{{ acme_intermediates[0].subject_key_identifier }}"
|
||||||
issuer: "{{ acme_roots[1].subject }}"
|
- test_certificates: last
|
||||||
use_csr_content: true
|
issuer: "{{ acme_roots[1].subject }}"
|
||||||
- name: Store obtain results for cert 6
|
use_csr_content: true
|
||||||
set_fact:
|
- name: Store obtain results for cert 6
|
||||||
cert_6_obtain_results: "{{ certificate_obtain_result }}"
|
set_fact:
|
||||||
cert_6_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
|
cert_6_obtain_results: "{{ certificate_obtain_result }}"
|
||||||
- name: Obtain cert 7
|
cert_6_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
|
||||||
include_tasks: obtain-cert.yml
|
when: acme_intermediates[0].subject_key_identifier is defined
|
||||||
vars:
|
- block:
|
||||||
certgen_title: Certificate 7
|
- name: Obtain cert 7
|
||||||
certificate_name: cert-7
|
include_tasks: obtain-cert.yml
|
||||||
key_type: rsa
|
vars:
|
||||||
rsa_bits: "{{ default_rsa_key_size }}"
|
certgen_title: Certificate 7
|
||||||
subject_alt_name:
|
certificate_name: cert-7
|
||||||
- "IP:127.0.0.1"
|
key_type: rsa
|
||||||
# - "IP:::1"
|
rsa_bits: "{{ default_rsa_key_size }}"
|
||||||
subject_alt_name_critical: no
|
subject_alt_name:
|
||||||
account_key: account-ec256
|
- "IP:127.0.0.1"
|
||||||
challenge: http-01
|
# - "IP:::1"
|
||||||
modify_account: yes
|
subject_alt_name_critical: no
|
||||||
deactivate_authzs: no
|
account_key: account-ec256
|
||||||
force: no
|
challenge: http-01
|
||||||
remaining_days: 10
|
modify_account: yes
|
||||||
terms_agreed: yes
|
deactivate_authzs: no
|
||||||
account_email: "example@example.org"
|
force: no
|
||||||
acme_expected_root_number: 2
|
remaining_days: 10
|
||||||
select_chain:
|
terms_agreed: yes
|
||||||
- test_certificates: last
|
account_email: "example@example.org"
|
||||||
authority_key_identifier: "{{ acme_roots[2].subject_key_identifier }}"
|
acme_expected_root_number: 2
|
||||||
use_csr_content: false
|
select_chain:
|
||||||
- name: Store obtain results for cert 7
|
- test_certificates: last
|
||||||
set_fact:
|
authority_key_identifier: "{{ acme_roots[2].subject_key_identifier }}"
|
||||||
cert_7_obtain_results: "{{ certificate_obtain_result }}"
|
use_csr_content: false
|
||||||
cert_7_alternate: "{{ 2 if select_crypto_backend == 'cryptography' else 0 }}"
|
- name: Store obtain results for cert 7
|
||||||
- name: Obtain cert 8
|
set_fact:
|
||||||
include_tasks: obtain-cert.yml
|
cert_7_obtain_results: "{{ certificate_obtain_result }}"
|
||||||
vars:
|
cert_7_alternate: "{{ 2 if select_crypto_backend == 'cryptography' else 0 }}"
|
||||||
certgen_title: Certificate 8
|
when: acme_roots[2].subject_key_identifier is defined
|
||||||
certificate_name: cert-8
|
- block:
|
||||||
key_type: rsa
|
- name: Obtain cert 8
|
||||||
rsa_bits: "{{ default_rsa_key_size }}"
|
include_tasks: obtain-cert.yml
|
||||||
subject_alt_name:
|
vars:
|
||||||
- "IP:127.0.0.1"
|
certgen_title: Certificate 8
|
||||||
# IPv4 only since our test validation server doesn't work
|
certificate_name: cert-8
|
||||||
# with IPv6 (thanks to Python's socketserver).
|
key_type: rsa
|
||||||
subject_alt_name_critical: no
|
rsa_bits: "{{ default_rsa_key_size }}"
|
||||||
account_key: account-ec256
|
subject_alt_name:
|
||||||
challenge: tls-alpn-01
|
- "IP:127.0.0.1"
|
||||||
challenge_alpn_tls: acme_challenge_cert_helper
|
# IPv4 only since our test validation server doesn't work
|
||||||
modify_account: yes
|
# with IPv6 (thanks to Python's socketserver).
|
||||||
deactivate_authzs: no
|
subject_alt_name_critical: no
|
||||||
force: no
|
account_key: account-ec256
|
||||||
remaining_days: 10
|
challenge: tls-alpn-01
|
||||||
terms_agreed: yes
|
challenge_alpn_tls: acme_challenge_cert_helper
|
||||||
account_email: "example@example.org"
|
modify_account: yes
|
||||||
use_csr_content: true
|
deactivate_authzs: no
|
||||||
- name: Store obtain results for cert 8
|
force: no
|
||||||
set_fact:
|
remaining_days: 10
|
||||||
cert_8_obtain_results: "{{ certificate_obtain_result }}"
|
terms_agreed: yes
|
||||||
cert_8_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
|
account_email: "example@example.org"
|
||||||
|
use_csr_content: true
|
||||||
|
- name: Store obtain results for cert 8
|
||||||
|
set_fact:
|
||||||
|
cert_8_obtain_results: "{{ certificate_obtain_result }}"
|
||||||
|
cert_8_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
|
||||||
|
when: cryptography_version.stdout is version('1.3', '>=')
|
||||||
## DISSECT CERTIFICATES #######################################################################
|
## DISSECT CERTIFICATES #######################################################################
|
||||||
# Make sure certificates are valid. Root certificate for Pebble equals the chain certificate.
|
# Make sure certificates are valid. Root certificate for Pebble equals the chain certificate.
|
||||||
- name: Verifying cert 1
|
- name: Verifying cert 1
|
||||||
|
@ -376,14 +382,17 @@
|
||||||
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-6-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-6-chain.pem" "{{ remote_tmp_dir }}/cert-6.pem"'
|
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-6-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-6-chain.pem" "{{ remote_tmp_dir }}/cert-6.pem"'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: cert_6_valid
|
register: cert_6_valid
|
||||||
|
when: acme_intermediates[0].subject_key_identifier is defined
|
||||||
- name: Verifying cert 7
|
- name: Verifying cert 7
|
||||||
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-7-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-7-chain.pem" "{{ remote_tmp_dir }}/cert-7.pem"'
|
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-7-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-7-chain.pem" "{{ remote_tmp_dir }}/cert-7.pem"'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: cert_7_valid
|
register: cert_7_valid
|
||||||
|
when: acme_roots[2].subject_key_identifier is defined
|
||||||
- name: Verifying cert 8
|
- name: Verifying cert 8
|
||||||
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-8-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-8-chain.pem" "{{ remote_tmp_dir }}/cert-8.pem"'
|
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-8-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-8-chain.pem" "{{ remote_tmp_dir }}/cert-8.pem"'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: cert_8_valid
|
register: cert_8_valid
|
||||||
|
when: cryptography_version.stdout is version('1.3', '>=')
|
||||||
# Dump certificate info
|
# Dump certificate info
|
||||||
- name: Dumping cert 1
|
- name: Dumping cert 1
|
||||||
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-1.pem" -noout -text'
|
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-1.pem" -noout -text'
|
||||||
|
@ -403,12 +412,15 @@
|
||||||
- name: Dumping cert 6
|
- name: Dumping cert 6
|
||||||
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-6.pem" -noout -text'
|
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-6.pem" -noout -text'
|
||||||
register: cert_6_text
|
register: cert_6_text
|
||||||
|
when: acme_intermediates[0].subject_key_identifier is defined
|
||||||
- name: Dumping cert 7
|
- name: Dumping cert 7
|
||||||
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-7.pem" -noout -text'
|
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-7.pem" -noout -text'
|
||||||
register: cert_7_text
|
register: cert_7_text
|
||||||
|
when: acme_roots[2].subject_key_identifier is defined
|
||||||
- name: Dumping cert 8
|
- name: Dumping cert 8
|
||||||
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-8.pem" -noout -text'
|
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-8.pem" -noout -text'
|
||||||
register: cert_8_text
|
register: cert_8_text
|
||||||
|
when: cryptography_version.stdout is version('1.3', '>=')
|
||||||
# Dump certificate info
|
# Dump certificate info
|
||||||
- name: Dumping cert 1
|
- name: Dumping cert 1
|
||||||
x509_certificate_info:
|
x509_certificate_info:
|
||||||
|
@ -434,14 +446,17 @@
|
||||||
x509_certificate_info:
|
x509_certificate_info:
|
||||||
path: "{{ remote_tmp_dir }}/cert-6.pem"
|
path: "{{ remote_tmp_dir }}/cert-6.pem"
|
||||||
register: cert_6_info
|
register: cert_6_info
|
||||||
|
when: acme_intermediates[0].subject_key_identifier is defined
|
||||||
- name: Dumping cert 7
|
- name: Dumping cert 7
|
||||||
x509_certificate_info:
|
x509_certificate_info:
|
||||||
path: "{{ remote_tmp_dir }}/cert-7.pem"
|
path: "{{ remote_tmp_dir }}/cert-7.pem"
|
||||||
register: cert_7_info
|
register: cert_7_info
|
||||||
|
when: acme_roots[2].subject_key_identifier is defined
|
||||||
- name: Dumping cert 8
|
- name: Dumping cert 8
|
||||||
x509_certificate_info:
|
x509_certificate_info:
|
||||||
path: "{{ remote_tmp_dir }}/cert-8.pem"
|
path: "{{ remote_tmp_dir }}/cert-8.pem"
|
||||||
register: cert_8_info
|
register: cert_8_info
|
||||||
|
when: cryptography_version.stdout is version('1.3', '>=')
|
||||||
## GET ACCOUNT ORDERS #########################################################################
|
## GET ACCOUNT ORDERS #########################################################################
|
||||||
- name: Don't retrieve orders
|
- name: Don't retrieve orders
|
||||||
acme_account_info:
|
acme_account_info:
|
||||||
|
|
|
@ -124,14 +124,38 @@
|
||||||
that:
|
that:
|
||||||
- cert_5_recreate_3 == True
|
- cert_5_recreate_3 == True
|
||||||
|
|
||||||
- name: Check that certificate 6 is valid
|
- block:
|
||||||
assert:
|
- name: Check that certificate 6 is valid
|
||||||
that:
|
assert:
|
||||||
- cert_6_valid is not failed
|
that:
|
||||||
- name: Check that certificate 6 contains correct SANs
|
- cert_6_valid is not failed
|
||||||
assert:
|
- name: Check that certificate 6 contains correct SANs
|
||||||
that:
|
assert:
|
||||||
- "'DNS:example.org' in cert_6_text.stdout"
|
that:
|
||||||
|
- "'DNS:example.org' in cert_6_text.stdout"
|
||||||
|
when: acme_intermediates[0].subject_key_identifier is defined
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Check that certificate 7 is valid
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cert_7_valid is not failed
|
||||||
|
- name: Check that certificate 7 contains correct SANs
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "'IP Address:127.0.0.1' in cert_8_text.stdout or 'IP:127.0.0.1' in cert_8_text.stdout"
|
||||||
|
when: acme_roots[2].subject_key_identifier is defined
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Check that certificate 8 is valid
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cert_8_valid is not failed
|
||||||
|
- name: Check that certificate 8 contains correct SANs
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "'IP Address:127.0.0.1' in cert_8_text.stdout or 'IP:127.0.0.1' in cert_8_text.stdout"
|
||||||
|
when: cryptography_version.stdout is version('1.3', '>=')
|
||||||
|
|
||||||
- name: Validate that orders were not retrieved
|
- name: Validate that orders were not retrieved
|
||||||
assert:
|
assert:
|
||||||
|
|
|
@ -31,4 +31,4 @@
|
||||||
terms_agreed: yes
|
terms_agreed: yes
|
||||||
account_email: "example@example.org"
|
account_email: "example@example.org"
|
||||||
|
|
||||||
when: openssl_version.stdout is version('1.0.0', '>=') or cryptography_version.stdout is version('1.5', '>=')
|
when: cryptography_version.stdout is version('1.5', '>=')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
- setup_acme
|
- setup_acme
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -4,16 +4,35 @@
|
||||||
# and should not be used as examples of how to write Ansible roles #
|
# and should not be used as examples of how to write Ansible roles #
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
skip_tests: false
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
|
|
||||||
- name: Get servers certificate with backend auto-detection
|
- name: Get servers certificate with backend auto-detection
|
||||||
get_certificate:
|
get_certificate:
|
||||||
host: "{{ httpbin_host }}"
|
host: "{{ httpbin_host }}"
|
||||||
port: 443
|
port: 443
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
skip_tests: |
|
||||||
|
{{
|
||||||
|
result is failed and (
|
||||||
|
'error: [Errno 1] _ssl.c:492: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure' in result.msg
|
||||||
|
or
|
||||||
|
'error: _ssl.c:314: Invalid SSL protocol variant specified.' in result.msg
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is success or skip_tests
|
||||||
|
|
||||||
when: |
|
when: |
|
||||||
pyopenssl_version.stdout is version('0.15', '>=') or
|
pyopenssl_version.stdout is version('0.15', '>=') or
|
||||||
(cryptography_version.stdout is version('1.6', '>=') and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6))
|
cryptography_version.stdout is version('1.6', '>=')
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
|
|
||||||
|
@ -21,7 +40,7 @@
|
||||||
vars:
|
vars:
|
||||||
select_crypto_backend: pyopenssl
|
select_crypto_backend: pyopenssl
|
||||||
|
|
||||||
when: pyopenssl_version.stdout is version('0.15', '>=')
|
when: pyopenssl_version.stdout is version('0.15', '>=') and not skip_tests
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
|
|
||||||
|
@ -32,6 +51,4 @@
|
||||||
# The module doesn't work with CentOS 6. Since the pyOpenSSL installed there is too old,
|
# The module doesn't work with CentOS 6. Since the pyOpenSSL installed there is too old,
|
||||||
# we never noticed before. This becomes a problem with the new cryptography backend,
|
# we never noticed before. This becomes a problem with the new cryptography backend,
|
||||||
# since there is a new enough cryptography version...
|
# since there is a new enough cryptography version...
|
||||||
when: |
|
when: cryptography_version.stdout is version('1.6', '>=') and not skip_tests
|
||||||
cryptography_version.stdout is version('1.6', '>=') and
|
|
||||||
(ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
|
|
||||||
|
|
|
@ -2,3 +2,4 @@ dependencies:
|
||||||
- setup_openssl
|
- setup_openssl
|
||||||
- setup_pyopenssl
|
- setup_pyopenssl
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -2,3 +2,4 @@ dependencies:
|
||||||
- setup_openssl
|
- setup_openssl
|
||||||
- setup_pyopenssl
|
- setup_pyopenssl
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -2,3 +2,4 @@ dependencies:
|
||||||
- setup_openssl
|
- setup_openssl
|
||||||
- setup_pyopenssl
|
- setup_pyopenssl
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
# Copyright 2007 Pallets
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. 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.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
from jinja2.filters import contextfilter
|
||||||
|
from jinja2.runtime import Undefined
|
||||||
|
from jinja2.exceptions import TemplateRuntimeError, FilterArgumentError
|
||||||
|
|
||||||
|
try:
|
||||||
|
from jinja2.nodes import EvalContext
|
||||||
|
HAS_EVALCONTEXT = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_EVALCONTEXT = False
|
||||||
|
|
||||||
|
|
||||||
|
def call_test(environment, test_name, value, args, kwargs):
|
||||||
|
try:
|
||||||
|
return environment.call_test(test_name, value, args, kwargs)
|
||||||
|
except AttributeError:
|
||||||
|
# call_test was added together with selectattr...
|
||||||
|
func = environment.tests.get(test_name)
|
||||||
|
if func is None:
|
||||||
|
raise TemplateRuntimeError('no test named %r' % test_name)
|
||||||
|
return func(value, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def call_filter(environment, name, value, args=None, kwargs=None,
|
||||||
|
context=None, eval_ctx=None):
|
||||||
|
func = environment.filters.get(name)
|
||||||
|
if func is None:
|
||||||
|
raise TemplateRuntimeError('no filter named %r' % name)
|
||||||
|
args = list(args or ())
|
||||||
|
if getattr(func, 'contextfilter', False):
|
||||||
|
if context is None:
|
||||||
|
raise TemplateRuntimeError('Attempted to invoke context filter without context')
|
||||||
|
args.insert(0, context)
|
||||||
|
elif getattr(func, 'evalcontextfilter', False):
|
||||||
|
if eval_ctx is None:
|
||||||
|
if context is not None:
|
||||||
|
eval_ctx = context.eval_ctx
|
||||||
|
elif HAS_EVALCONTEXT:
|
||||||
|
eval_ctx = EvalContext(environment)
|
||||||
|
else:
|
||||||
|
raise TemplateRuntimeError('Too old Jinja2 does not have EvalContext')
|
||||||
|
args.insert(0, eval_ctx)
|
||||||
|
elif getattr(func, 'environmentfilter', False):
|
||||||
|
args.insert(0, environment)
|
||||||
|
return func(value, *args, **(kwargs or {}))
|
||||||
|
|
||||||
|
|
||||||
|
def make_attrgetter(environment, attribute_str, default=None):
|
||||||
|
attributes = [int(attribute) if attribute.isdigit() else attribute for attribute in attribute_str.split(".")]
|
||||||
|
|
||||||
|
def f(item):
|
||||||
|
for attribute in attributes:
|
||||||
|
item = environment.getitem(item, attribute)
|
||||||
|
if default and isinstance(item, Undefined):
|
||||||
|
item = default
|
||||||
|
return item
|
||||||
|
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
@contextfilter
|
||||||
|
def compatibility_selectattr_filter(context, sequence, attribute_str, test_name, *args, **kwargs):
|
||||||
|
f = make_attrgetter(context.environment, attribute_str)
|
||||||
|
for item in sequence:
|
||||||
|
if call_test(context.environment, test_name, f(item), args, kwargs):
|
||||||
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_map(context, args, kwargs):
|
||||||
|
if len(args) == 0 and "attribute" in kwargs:
|
||||||
|
attribute = kwargs.pop("attribute")
|
||||||
|
default = kwargs.pop("default", None)
|
||||||
|
if kwargs:
|
||||||
|
raise FilterArgumentError("Unexpected keyword argument {0!r}".format(next(iter(kwargs))))
|
||||||
|
func = make_attrgetter(context.environment, attribute, default=default)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
name = args[0]
|
||||||
|
args = args[1:]
|
||||||
|
except LookupError:
|
||||||
|
raise FilterArgumentError("map requires a filter argument")
|
||||||
|
|
||||||
|
def func(item):
|
||||||
|
return call_filter(context.environment, name, item, args, kwargs, context=context)
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
@contextfilter
|
||||||
|
def compatibility_map_filter(context, seq, *args, **kwargs):
|
||||||
|
func = prepare_map(context, args, kwargs)
|
||||||
|
if seq:
|
||||||
|
for item in seq:
|
||||||
|
yield func(item)
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule:
|
||||||
|
''' Jinja2 compat filters '''
|
||||||
|
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'selectattr': compatibility_selectattr_filter,
|
||||||
|
'map': compatibility_map_filter,
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
---
|
|
@ -2,6 +2,10 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
def compatibility_equalto_test(a, b):
|
||||||
|
return a == b
|
||||||
|
|
||||||
|
|
||||||
def compatibility_in_test(a, b):
|
def compatibility_in_test(a, b):
|
||||||
return a in b
|
return a in b
|
||||||
|
|
||||||
|
@ -11,5 +15,6 @@ class TestModule:
|
||||||
|
|
||||||
def tests(self):
|
def tests(self):
|
||||||
return {
|
return {
|
||||||
|
'equalto': compatibility_equalto_test,
|
||||||
'in': compatibility_in_test,
|
'in': compatibility_in_test,
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
'secp384r1' if key_type == 'ec384' else
|
'secp384r1' if key_type == 'ec384' else
|
||||||
'secp521r1' if key_type == 'ec521' else
|
'secp521r1' if key_type == 'ec521' else
|
||||||
'invalid value for key_type!' }}
|
'invalid value for key_type!' }}
|
||||||
passphrase: "{{ certificate_passphrase | default(omit, true) }}"
|
passphrase: "{{ certificate_passphrase | default(omit) | default(omit, true) }}"
|
||||||
cipher: "{{ 'auto' if certificate_passphrase | default() else omit }}"
|
cipher: "{{ 'auto' if certificate_passphrase | default() else omit }}"
|
||||||
force: true
|
force: true
|
||||||
## CSR ########################################################################################
|
## CSR ########################################################################################
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
openssl_csr:
|
openssl_csr:
|
||||||
path: "{{ remote_tmp_dir }}/{{ certificate_name }}.csr"
|
path: "{{ remote_tmp_dir }}/{{ certificate_name }}.csr"
|
||||||
privatekey_path: "{{ remote_tmp_dir }}/{{ certificate_name }}.key"
|
privatekey_path: "{{ remote_tmp_dir }}/{{ certificate_name }}.key"
|
||||||
privatekey_passphrase: "{{ certificate_passphrase | default(omit, true) }}"
|
privatekey_passphrase: "{{ certificate_passphrase | default(omit) | default(omit, true) }}"
|
||||||
subject_alt_name: "{{ subject_alt_name }}"
|
subject_alt_name: "{{ subject_alt_name }}"
|
||||||
subject_alt_name_critical: "{{ subject_alt_name_critical }}"
|
subject_alt_name_critical: "{{ subject_alt_name_critical }}"
|
||||||
return_content: true
|
return_content: true
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
validate_certs: no
|
validate_certs: no
|
||||||
account_key: "{{ (remote_tmp_dir ~ '/' ~ account_key ~ '.pem') if account_key_content is not defined else omit }}"
|
account_key: "{{ (remote_tmp_dir ~ '/' ~ account_key ~ '.pem') if account_key_content is not defined else omit }}"
|
||||||
account_key_content: "{{ account_key_content | default(omit) }}"
|
account_key_content: "{{ account_key_content | default(omit) }}"
|
||||||
account_key_passphrase: "{{ account_key_passphrase | default(omit, true) }}"
|
account_key_passphrase: "{{ account_key_passphrase | default(omit) | default(omit, true) }}"
|
||||||
modify_account: "{{ modify_account }}"
|
modify_account: "{{ modify_account }}"
|
||||||
csr: "{{ omit if use_csr_content | default(false) else remote_tmp_dir ~ '/' ~ certificate_name ~ '.csr' }}"
|
csr: "{{ omit if use_csr_content | default(false) else remote_tmp_dir ~ '/' ~ certificate_name ~ '.csr' }}"
|
||||||
csr_content: "{{ csr_result.csr if use_csr_content | default(false) else omit }}"
|
csr_content: "{{ csr_result.csr if use_csr_content | default(false) else omit }}"
|
||||||
|
@ -68,21 +68,21 @@
|
||||||
body: "{{ item.value }}"
|
body: "{{ item.value }}"
|
||||||
with_dict: "{{ challenge_data.challenge_data_dns }}"
|
with_dict: "{{ challenge_data.challenge_data_dns }}"
|
||||||
when: "challenge_data is changed and challenge == 'dns-01'"
|
when: "challenge_data is changed and challenge == 'dns-01'"
|
||||||
- name: ({{ certgen_title }}) Create TLS ALPN challenges (acm_challenge_cert_helper)
|
- name: ({{ certgen_title }}) Create TLS ALPN challenges (acme_challenge_cert_helper)
|
||||||
acme_challenge_cert_helper:
|
acme_challenge_cert_helper:
|
||||||
challenge: tls-alpn-01
|
challenge: tls-alpn-01
|
||||||
challenge_data: "{{ item.value['tls-alpn-01'] }}"
|
challenge_data: "{{ item.value['tls-alpn-01'] }}"
|
||||||
private_key_src: "{{ remote_tmp_dir }}/{{ certificate_name }}.key"
|
private_key_src: "{{ remote_tmp_dir }}/{{ certificate_name }}.key"
|
||||||
private_key_passphrase: "{{ certificate_passphrase | default(omit, true) }}"
|
private_key_passphrase: "{{ certificate_passphrase | default(omit) | default(omit, true) }}"
|
||||||
with_dict: "{{ challenge_data.challenge_data if challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is defined and challenge_alpn_tls == 'acme_challenge_cert_helper') else {} }}"
|
with_dict: "{{ challenge_data.challenge_data if challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'acme_challenge_cert_helper') else {} }}"
|
||||||
register: tls_alpn_challenges
|
register: tls_alpn_challenges
|
||||||
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is defined and challenge_alpn_tls == 'acme_challenge_cert_helper')"
|
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'acme_challenge_cert_helper')"
|
||||||
- name: ({{ certgen_title }}) Read private key
|
- name: ({{ certgen_title }}) Read private key
|
||||||
slurp:
|
slurp:
|
||||||
src: '{{ remote_tmp_dir }}/{{ certificate_name }}.key'
|
src: '{{ remote_tmp_dir }}/{{ certificate_name }}.key'
|
||||||
register: slurp
|
register: slurp
|
||||||
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is defined and challenge_alpn_tls == 'acme_challenge_cert_helper')"
|
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'acme_challenge_cert_helper')"
|
||||||
- name: ({{ certgen_title }}) Set TLS ALPN challenges (acm_challenge_cert_helper)
|
- name: ({{ certgen_title }}) Set TLS ALPN challenges (acme_challenge_cert_helper)
|
||||||
uri:
|
uri:
|
||||||
url: "http://{{ acme_host }}:5000/tls-alpn/{{ item.domain }}/{{ item.identifier }}/certificate-and-key"
|
url: "http://{{ acme_host }}:5000/tls-alpn/{{ item.domain }}/{{ item.identifier }}/certificate-and-key"
|
||||||
method: PUT
|
method: PUT
|
||||||
|
@ -90,8 +90,8 @@
|
||||||
body: "{{ item.challenge_certificate }}\n{{ slurp.content | b64decode }}"
|
body: "{{ item.challenge_certificate }}\n{{ slurp.content | b64decode }}"
|
||||||
headers:
|
headers:
|
||||||
content-type: "application/pem-certificate-chain"
|
content-type: "application/pem-certificate-chain"
|
||||||
with_items: "{{ tls_alpn_challenges.results if challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is defined and challenge_alpn_tls == 'acme_challenge_cert_helper') else [] }}"
|
with_items: "{{ tls_alpn_challenges.results if challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'acme_challenge_cert_helper') else [] }}"
|
||||||
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is defined and challenge_alpn_tls == 'acme_challenge_cert_helper')"
|
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'acme_challenge_cert_helper')"
|
||||||
- name: ({{ certgen_title }}) Create TLS ALPN challenges (der-value-b64)
|
- name: ({{ certgen_title }}) Create TLS ALPN challenges (der-value-b64)
|
||||||
uri:
|
uri:
|
||||||
url: "http://{{ acme_host }}:5000/tls-alpn/{{ item.value['tls-alpn-01'].resource }}/{{ item.value['tls-alpn-01'].resource_original }}/der-value-b64"
|
url: "http://{{ acme_host }}:5000/tls-alpn/{{ item.value['tls-alpn-01'].resource }}/{{ item.value['tls-alpn-01'].resource_original }}/der-value-b64"
|
||||||
|
@ -100,8 +100,8 @@
|
||||||
body: "{{ item.value['tls-alpn-01'].resource_value }}"
|
body: "{{ item.value['tls-alpn-01'].resource_value }}"
|
||||||
headers:
|
headers:
|
||||||
content-type: "application/octet-stream"
|
content-type: "application/octet-stream"
|
||||||
with_dict: "{{ challenge_data.challenge_data if challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is not defined or challenge_alpn_tls == 'der-value-b64') else [] }}"
|
with_dict: "{{ challenge_data.challenge_data if challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'der-value-b64') else {} }}"
|
||||||
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls is not defined or challenge_alpn_tls == 'der-value-b64')"
|
when: "challenge_data is changed and challenge == 'tls-alpn-01' and (challenge_alpn_tls | default('der-value-b64') == 'der-value-b64')"
|
||||||
## ACME STEP 2 ################################################################################
|
## ACME STEP 2 ################################################################################
|
||||||
- name: ({{ certgen_title }}) Obtain cert, step 2
|
- name: ({{ certgen_title }}) Obtain cert, step 2
|
||||||
acme_certificate:
|
acme_certificate:
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
validate_certs: no
|
validate_certs: no
|
||||||
account_key: "{{ (remote_tmp_dir ~ '/' ~ account_key ~ '.pem') if account_key_content is not defined else omit }}"
|
account_key: "{{ (remote_tmp_dir ~ '/' ~ account_key ~ '.pem') if account_key_content is not defined else omit }}"
|
||||||
account_key_content: "{{ account_key_content | default(omit) }}"
|
account_key_content: "{{ account_key_content | default(omit) }}"
|
||||||
account_key_passphrase: "{{ account_key_passphrase | default(omit, true) }}"
|
account_key_passphrase: "{{ account_key_passphrase | default(omit) | default(omit, true) }}"
|
||||||
account_uri: "{{ challenge_data.account_uri }}"
|
account_uri: "{{ challenge_data.account_uri }}"
|
||||||
modify_account: "{{ modify_account }}"
|
modify_account: "{{ modify_account }}"
|
||||||
csr: "{{ omit if use_csr_content | default(false) else remote_tmp_dir ~ '/' ~ certificate_name ~ '.csr' }}"
|
csr: "{{ omit if use_csr_content | default(false) else remote_tmp_dir ~ '/' ~ certificate_name ~ '.csr' }}"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
|
- setup_python_info
|
||||||
- setup_remote_constraints
|
- setup_remote_constraints
|
||||||
- setup_pkg_mgr
|
- setup_pkg_mgr
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
command: "{{ ansible_python.executable }} -c 'import os; print(dict(os.environ))'"
|
command: "{{ ansible_python.executable }} -c 'import os; print(dict(os.environ))'"
|
||||||
register: sys_environment
|
register: sys_environment
|
||||||
|
|
||||||
- debug: var=sys_environment
|
- name: Show system environment
|
||||||
|
debug:
|
||||||
|
var: sys_environment.stdout_lines
|
||||||
|
|
||||||
- name: Default value for OpenSSL binary path
|
- name: Default value for OpenSSL binary path
|
||||||
set_fact:
|
set_fact:
|
||||||
|
@ -18,14 +20,19 @@
|
||||||
include_vars: '{{ ansible_os_family }}.yml'
|
include_vars: '{{ ansible_os_family }}.yml'
|
||||||
when: not ansible_os_family == "Darwin"
|
when: not ansible_os_family == "Darwin"
|
||||||
|
|
||||||
|
- name: Check whether OpenSSL is there
|
||||||
|
command: "{{ openssl_binary }} version"
|
||||||
|
register: openssl_version_full
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Install OpenSSL
|
- name: Install OpenSSL
|
||||||
become: true
|
become: true
|
||||||
package:
|
package:
|
||||||
name: '{{ openssl_package_name }}'
|
name: '{{ openssl_package_name }}'
|
||||||
when: not ansible_os_family == 'Darwin'
|
when: not ansible_os_family == 'Darwin' and openssl_version_full is failed
|
||||||
|
|
||||||
- name: Register openssl version (full)
|
- name: Register openssl version (full)
|
||||||
shell: "{{ openssl_binary }} version"
|
command: "{{ openssl_binary }} version"
|
||||||
register: openssl_version_full
|
register: openssl_version_full
|
||||||
|
|
||||||
- name: Show openssl version (full)
|
- name: Show openssl version (full)
|
||||||
|
@ -60,7 +67,7 @@
|
||||||
openssl_binary: "{{ brew_openssl_prefix.stdout }}/bin/openssl"
|
openssl_binary: "{{ brew_openssl_prefix.stdout }}/bin/openssl"
|
||||||
|
|
||||||
- name: MACOS | Register openssl version (full)
|
- name: MACOS | Register openssl version (full)
|
||||||
shell: "{{ openssl_binary }} version"
|
command: "{{ openssl_binary }} version"
|
||||||
register: openssl_version_full_again
|
register: openssl_version_full_again
|
||||||
# We must use a different variable to prevent the 'when' condition of the surrounding block to fail
|
# We must use a different variable to prevent the 'when' condition of the surrounding block to fail
|
||||||
|
|
||||||
|
@ -69,29 +76,37 @@
|
||||||
var: openssl_version_full_again.stdout_lines
|
var: openssl_version_full_again.stdout_lines
|
||||||
|
|
||||||
- name: Register openssl version
|
- name: Register openssl version
|
||||||
shell: "{{ openssl_binary }} version | cut -d' ' -f2"
|
shell: "{{ openssl_binary }} version | cut -d' ' -f2"
|
||||||
register: openssl_version
|
register: openssl_version
|
||||||
|
|
||||||
- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
|
- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
|
||||||
block:
|
block:
|
||||||
- name: Install cryptography (Python 3)
|
|
||||||
become: true
|
|
||||||
package:
|
|
||||||
name: '{{ cryptography_package_name_python3 }}'
|
|
||||||
when: not ansible_os_family == 'Darwin' and ansible_python_version is version('3.0', '>=')
|
|
||||||
|
|
||||||
- name: Install cryptography (Python 2)
|
- name: Install from system packages
|
||||||
become: true
|
when: ansible_os_family != "Darwin" and target_system_python
|
||||||
package:
|
block:
|
||||||
name: '{{ cryptography_package_name }}'
|
|
||||||
when: not ansible_os_family == 'Darwin' and ansible_python_version is version('3.0', '<')
|
|
||||||
|
|
||||||
- name: Install cryptography (Darwin)
|
- name: Install cryptography (Python 3 from system packages)
|
||||||
become: true
|
become: true
|
||||||
pip:
|
package:
|
||||||
name: cryptography>=3.3
|
name: '{{ cryptography_package_name_python3 }}'
|
||||||
extra_args: "-c {{ remote_constraints }}"
|
when: ansible_python_version is version('3.0', '>=')
|
||||||
when: ansible_os_family == 'Darwin'
|
|
||||||
|
- name: Install cryptography (Python 2 from system packages)
|
||||||
|
become: true
|
||||||
|
package:
|
||||||
|
name: '{{ cryptography_package_name }}'
|
||||||
|
when: ansible_python_version is version('3.0', '<')
|
||||||
|
|
||||||
|
- name: Install from PyPi
|
||||||
|
when: ansible_os_family == "Darwin" or not target_system_python
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Install cryptography (PyPi)
|
||||||
|
become: true
|
||||||
|
pip:
|
||||||
|
name: 'cryptography{% if ansible_os_family == "Darwin" %}>=3.3{% endif %}'
|
||||||
|
extra_args: "-c {{ remote_constraints }}"
|
||||||
|
|
||||||
- name: Register cryptography version
|
- name: Register cryptography version
|
||||||
command: "{{ ansible_python.executable }} -c 'import cryptography; print(cryptography.__version__)'"
|
command: "{{ ansible_python.executable }} -c 'import cryptography; print(cryptography.__version__)'"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
|
- setup_python_info
|
||||||
- setup_remote_constraints
|
- setup_remote_constraints
|
||||||
- setup_pkg_mgr
|
- setup_pkg_mgr
|
||||||
|
|
|
@ -4,28 +4,34 @@
|
||||||
# and should not be used as examples of how to write Ansible roles #
|
# and should not be used as examples of how to write Ansible roles #
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
- name: Include OS-specific variables
|
- name: Install from system packages
|
||||||
include_vars: '{{ ansible_os_family }}.yml'
|
when: ansible_os_family != "Darwin" and target_system_python
|
||||||
when: not ansible_os_family == "Darwin"
|
block:
|
||||||
|
|
||||||
- name: Install pyOpenSSL (Python 3)
|
- name: Include OS-specific variables
|
||||||
become: true
|
include_vars: '{{ ansible_os_family }}.yml'
|
||||||
package:
|
|
||||||
name: '{{ pyopenssl_package_name_python3 }}'
|
|
||||||
when: not ansible_os_family == 'Darwin' and ansible_python_version is version('3.0', '>=')
|
|
||||||
|
|
||||||
- name: Install pyOpenSSL (Python 2)
|
- name: Install pyOpenSSL (Python 3 from system packages)
|
||||||
become: true
|
become: true
|
||||||
package:
|
package:
|
||||||
name: '{{ pyopenssl_package_name }}'
|
name: '{{ pyopenssl_package_name_python3 }}'
|
||||||
when: not ansible_os_family == 'Darwin' and ansible_python_version is version('3.0', '<')
|
when: ansible_python_version is version('3.0', '>=')
|
||||||
|
|
||||||
- name: Install pyOpenSSL (Darwin)
|
- name: Install pyOpenSSL (Python 2 from system packages)
|
||||||
become: true
|
become: true
|
||||||
pip:
|
package:
|
||||||
name: pyOpenSSL
|
name: '{{ pyopenssl_package_name }}'
|
||||||
extra_args: "-c {{ remote_constraints }}"
|
when: ansible_python_version is version('3.0', '<')
|
||||||
when: ansible_os_family == 'Darwin'
|
|
||||||
|
- name: Install from PyPi
|
||||||
|
when: ansible_os_family == "Darwin" or not target_system_python
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Install pyOpenSSL (PyPi)
|
||||||
|
become: true
|
||||||
|
pip:
|
||||||
|
name: pyOpenSSL
|
||||||
|
extra_args: "-c {{ remote_constraints }}"
|
||||||
|
|
||||||
- name: Register pyOpenSSL version
|
- name: Register pyOpenSSL version
|
||||||
command: "{{ ansible_python.executable }} -c 'import OpenSSL; print(OpenSSL.__version__)'"
|
command: "{{ ansible_python.executable }} -c 'import OpenSSL; print(OpenSSL.__version__)'"
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# (c) 2021, Felix Fontein <felix@fontein.de>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
def get_major_minor_version(version):
|
||||||
|
parts = version.split('.')[:2]
|
||||||
|
return '.'.join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
""" IP address and network manipulation filters """
|
||||||
|
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'internal__get_major_minor_version': get_major_minor_version,
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
- name: Gather facts on controller
|
||||||
|
setup:
|
||||||
|
gather_subset: '!all'
|
||||||
|
delegate_to: localhost
|
||||||
|
delegate_facts: true
|
||||||
|
run_once: true
|
||||||
|
- name: Show variables
|
||||||
|
debug:
|
||||||
|
msg: |-
|
||||||
|
Target:
|
||||||
|
Python: {{ ansible_facts.python.version.major ~ '.' ~ ansible_facts.python.version.minor }}
|
||||||
|
OS family: {{ ansible_facts.os_family }}
|
||||||
|
Distribution: {{ ansible_facts.distribution }}
|
||||||
|
Distribution version: {{ ansible_facts.distribution_version | internal__get_major_minor_version }}
|
||||||
|
Distribution major version: {{ ansible_facts.distribution_major_version }}
|
||||||
|
|
||||||
|
Controller:
|
||||||
|
Python: {{ hostvars['localhost'].ansible_facts.python.version.major ~ '.' ~ hostvars['localhost'].ansible_facts.python.version.minor }}
|
||||||
|
OS family: {{ hostvars['localhost'].ansible_facts.os_family }}
|
||||||
|
Distribution: {{ hostvars['localhost'].ansible_facts.distribution }}
|
||||||
|
Distribution version: {{ hostvars['localhost'].ansible_facts.distribution_version | internal__get_major_minor_version }}
|
||||||
|
Distribution major version: {{ hostvars['localhost'].ansible_facts.distribution_major_version }}
|
||||||
|
- name: Record information
|
||||||
|
set_fact:
|
||||||
|
target_system_python: >-
|
||||||
|
{{
|
||||||
|
(ansible_facts.python.version.major ~ '.' ~ ansible_facts.python.version.minor)
|
||||||
|
in
|
||||||
|
(
|
||||||
|
system_python_version_data[ansible_facts.distribution] |
|
||||||
|
default(system_python_version_data[ansible_facts.os_family])
|
||||||
|
)[ansible_facts.distribution_version | internal__get_major_minor_version]
|
||||||
|
| default(
|
||||||
|
(
|
||||||
|
system_python_version_data[ansible_facts.distribution] |
|
||||||
|
default(system_python_version_data[ansible_facts.os_family])
|
||||||
|
)[ansible_facts.distribution_major_version]
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
controller_system_python: >-
|
||||||
|
{{
|
||||||
|
(hostvars['localhost'].ansible_facts.python.version.major ~ '.' ~ hostvars['localhost'].ansible_facts.python.version.minor)
|
||||||
|
in
|
||||||
|
(
|
||||||
|
system_python_version_data[hostvars['localhost'].ansible_facts.distribution] |
|
||||||
|
default(system_python_version_data[hostvars['localhost'].ansible_facts.os_family])
|
||||||
|
)[ansible_facts.distribution_version | internal__get_major_minor_version]
|
||||||
|
| default(
|
||||||
|
(
|
||||||
|
system_python_version_data[hostvars['localhost'].ansible_facts.distribution] |
|
||||||
|
default(system_python_version_data[hostvars['localhost'].ansible_facts.os_family])
|
||||||
|
)[hostvars['localhost'].ansible_facts.distribution_major_version]
|
||||||
|
)
|
||||||
|
}}
|
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
system_python_version_data:
|
||||||
|
CentOS:
|
||||||
|
'6':
|
||||||
|
- '2.6'
|
||||||
|
'7':
|
||||||
|
- '2.7'
|
||||||
|
'8':
|
||||||
|
- '3.6'
|
||||||
|
Fedora:
|
||||||
|
'30':
|
||||||
|
- '3.7'
|
||||||
|
'31':
|
||||||
|
- '3.7'
|
||||||
|
'32':
|
||||||
|
- '3.8'
|
||||||
|
'33':
|
||||||
|
- '3.9'
|
||||||
|
'34':
|
||||||
|
- '3.9'
|
||||||
|
Ubuntu:
|
||||||
|
'16':
|
||||||
|
- '2.7'
|
||||||
|
'18':
|
||||||
|
- '3.6'
|
||||||
|
'20':
|
||||||
|
- '3.8'
|
||||||
|
Darwin:
|
||||||
|
'10.11':
|
||||||
|
- '2.7'
|
||||||
|
'10.15':
|
||||||
|
- '3.8'
|
||||||
|
'11.1':
|
||||||
|
- '3.9'
|
||||||
|
FreeBSD:
|
||||||
|
'12.1':
|
||||||
|
- '3.6'
|
||||||
|
'12.2':
|
||||||
|
- '3.7'
|
||||||
|
'13.0':
|
||||||
|
- '3.7'
|
||||||
|
RedHat:
|
||||||
|
'7':
|
||||||
|
- '2.7'
|
||||||
|
'8':
|
||||||
|
- '3.6'
|
||||||
|
Suse:
|
||||||
|
'15':
|
||||||
|
- '2.7'
|
||||||
|
- '3.6'
|
|
@ -1,3 +1,4 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
- setup_acme
|
- setup_acme
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -109,6 +109,13 @@
|
||||||
regexp: 'os\.remove\(wellknown_path\)'
|
regexp: 'os\.remove\(wellknown_path\)'
|
||||||
replace: 'pass'
|
replace: 'pass'
|
||||||
|
|
||||||
|
- name: "Monkey-patch acme-tiny: Allow to run with Python 2"
|
||||||
|
replace:
|
||||||
|
path: "{{ remote_tmp_dir }}/acme-tiny"
|
||||||
|
regexp: '#!/usr/bin/env python3'
|
||||||
|
replace: '#!/usr/bin/env python'
|
||||||
|
when: ansible_facts.python.version.major == 2
|
||||||
|
|
||||||
- name: Create challenges directory
|
- name: Create challenges directory
|
||||||
file:
|
file:
|
||||||
path: '{{ remote_tmp_dir }}/challenges'
|
path: '{{ remote_tmp_dir }}/challenges'
|
||||||
|
|
|
@ -2,3 +2,4 @@ dependencies:
|
||||||
- setup_openssl
|
- setup_openssl
|
||||||
- setup_pyopenssl
|
- setup_pyopenssl
|
||||||
- setup_remote_tmp_dir
|
- setup_remote_tmp_dir
|
||||||
|
- prepare_jinja2_compat
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
|
|
||||||
def compatibility_in_test(a, b):
|
|
||||||
return a in b
|
|
||||||
|
|
||||||
|
|
||||||
class TestModule:
|
|
||||||
''' Ansible math jinja2 tests '''
|
|
||||||
|
|
||||||
def tests(self):
|
|
||||||
return {
|
|
||||||
'in': compatibility_in_test,
|
|
||||||
}
|
|
Loading…
Reference in New Issue