Merge "TLS by default for the overcloud"
This commit is contained in:
commit
816b3a3453
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The default plan deployment workflow now automatically adds the necessary
|
||||||
|
certificate and key to enable TLS by default in the overcloud. Note that
|
||||||
|
this doesn't overwrite any certificate or keys given by the deployer;
|
||||||
|
those still take precedence. This will enable TLS if it isn't already
|
||||||
|
enabled though.
|
@ -28,3 +28,4 @@ python-keystoneclient>=3.8.0 # Apache-2.0
|
|||||||
keystoneauth1>=3.4.0 # Apache-2.0
|
keystoneauth1>=3.4.0 # Apache-2.0
|
||||||
tenacity>=4.4.0 # Apache-2.0
|
tenacity>=4.4.0 # Apache-2.0
|
||||||
futures>=3.0.0;python_version=='2.7' or python_version=='2.6' # BSD
|
futures>=3.0.0;python_version=='2.7' or python_version=='2.6' # BSD
|
||||||
|
cryptography>=2.1 # BSD/Apache-2.0
|
||||||
|
48
scripts/tripleo-overcloud-cert
Executable file
48
scripts/tripleo-overcloud-cert
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -x
|
||||||
|
# Currently action is unused, but it will be.
|
||||||
|
action=$1
|
||||||
|
overcloud_container_name=$2
|
||||||
|
|
||||||
|
if [[ "$action" == 'request' || "$action" == 'resubmit' ]]; then
|
||||||
|
overcloud_fqdn=$3
|
||||||
|
|
||||||
|
OVERCLOUD_CERT_PATH="/etc/pki/tls/certs/overcloud-${overcloud_container_name}-cert.pem"
|
||||||
|
OVERCLOUD_KEY_PATH="/etc/pki/tls/private/overcloud-${overcloud_container_name}-key.pem"
|
||||||
|
|
||||||
|
# This validates that overcloud_fqdn is actually an FQDN
|
||||||
|
if [[ ! $(echo "$overcloud_fqdn" | grep -P '(?=^.{1,254}$)(^(?>(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})$)') ]]
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Skip request if the request already exists
|
||||||
|
/usr/bin/getcert list -c local -i "overcloud-${overcloud_container_name}-cert" > /dev/null
|
||||||
|
request_exists=$?
|
||||||
|
if [[ $request_exists != 0 || "$action" == 'resubmit' ]];
|
||||||
|
then
|
||||||
|
if [[ "$action" == "request" ]]; then
|
||||||
|
/usr/bin/getcert request -c local \
|
||||||
|
-I "overcloud-${overcloud_container_name}-cert" \
|
||||||
|
-f $OVERCLOUD_CERT_PATH \
|
||||||
|
-k $OVERCLOUD_KEY_PATH \
|
||||||
|
-N "CN=${overcloud_fqdn}" \
|
||||||
|
-D "$overcloud_fqdn" \
|
||||||
|
-C "/usr/bin/chown mistral:mistral $OVERCLOUD_CERT_PATH $OVERCLOUD_KEY_PATH" \
|
||||||
|
-w -v
|
||||||
|
else
|
||||||
|
/usr/bin/getcert resubmit -c local \
|
||||||
|
-i "overcloud-${overcloud_container_name}-cert" \
|
||||||
|
-f $OVERCLOUD_CERT_PATH \
|
||||||
|
-N "CN=${overcloud_fqdn}" \
|
||||||
|
-D "$overcloud_fqdn" \
|
||||||
|
-C "/usr/bin/chown mistral:mistral $OVERCLOUD_CERT_PATH $OVERCLOUD_KEY_PATH" \
|
||||||
|
-w -v
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [[ "$action" == 'query' ]]; then
|
||||||
|
/usr/bin/getcert list -c local -i "overcloud-${overcloud_container_name}-cert"
|
||||||
|
else
|
||||||
|
echo "Unkown action $action"
|
||||||
|
exit 1
|
||||||
|
fi
|
@ -31,6 +31,7 @@ scripts =
|
|||||||
scripts/run-validation
|
scripts/run-validation
|
||||||
scripts/tripleo-build-images
|
scripts/tripleo-build-images
|
||||||
scripts/tripleo-config-download
|
scripts/tripleo-config-download
|
||||||
|
scripts/tripleo-overcloud-cert
|
||||||
scripts/upgrade-non-controller.sh
|
scripts/upgrade-non-controller.sh
|
||||||
scripts/upload-puppet-modules
|
scripts/upload-puppet-modules
|
||||||
scripts/upload-swift-artifacts
|
scripts/upload-swift-artifacts
|
||||||
|
1
sudoers
1
sudoers
@ -9,4 +9,5 @@ mistral ALL = NOPASSWD: /usr/bin/rm -f /tmp/validations_identity_[A-Za-z0-9_][A-
|
|||||||
mistral ALL = NOPASSWD: /bin/nova-manage cell_v2 discover_hosts *
|
mistral ALL = NOPASSWD: /bin/nova-manage cell_v2 discover_hosts *
|
||||||
mistral ALL = NOPASSWD: /usr/bin/tar --ignore-failed-read -C / -cf /var/tmp/undercloud-backup-*.tar *
|
mistral ALL = NOPASSWD: /usr/bin/tar --ignore-failed-read -C / -cf /var/tmp/undercloud-backup-*.tar *
|
||||||
mistral ALL = NOPASSWD: /usr/bin/chown mistral. /var/tmp/undercloud-backup-*/filesystem-*.tar
|
mistral ALL = NOPASSWD: /usr/bin/chown mistral. /var/tmp/undercloud-backup-*/filesystem-*.tar
|
||||||
|
mistral ALL = NOPASSWD: /usr/bin/tripleo-overcloud-cert *
|
||||||
validations ALL = NOPASSWD: ALL
|
validations ALL = NOPASSWD: ALL
|
||||||
|
@ -12,13 +12,17 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography import x509
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from heatclient.common import deployment_utils
|
from heatclient.common import deployment_utils
|
||||||
from heatclient import exc as heat_exc
|
from heatclient import exc as heat_exc
|
||||||
from mistral_lib import actions
|
from mistral_lib import actions
|
||||||
|
from oslo_concurrency import processutils
|
||||||
from swiftclient import exceptions as swiftexceptions
|
from swiftclient import exceptions as swiftexceptions
|
||||||
|
|
||||||
from tripleo_common.actions import base
|
from tripleo_common.actions import base
|
||||||
@ -203,11 +207,21 @@ class DeployStackAction(templates.ProcessTemplatesAction):
|
|||||||
return heat.stacks.update(stack.id, **stack_args)
|
return heat.stacks.update(stack.id, **stack_args)
|
||||||
|
|
||||||
def set_tls_parameters(self, parameters, env,
|
def set_tls_parameters(self, parameters, env,
|
||||||
local_ca_path=constants.LOCAL_CACERT_PATH):
|
local_ca_path=constants.LOCAL_CACERT_PATH,
|
||||||
|
overcloud_cert_path=constants.OVERCLOUD_CERT_PATH,
|
||||||
|
overcloud_key_path=constants.OVERCLOUD_KEY_PATH):
|
||||||
cacert_string = self._get_local_cacert(local_ca_path)
|
cacert_string = self._get_local_cacert(local_ca_path)
|
||||||
if cacert_string:
|
if not cacert_string:
|
||||||
parameters['CAMap'] = self._get_updated_camap_entry(
|
return
|
||||||
'undercloud-ca', cacert_string, self._get_camap(env))
|
|
||||||
|
parameters['CAMap'] = self._get_updated_camap_entry(
|
||||||
|
'undercloud-ca', cacert_string, self._get_camap(env))
|
||||||
|
cert_path = overcloud_cert_path.format(container=self.container)
|
||||||
|
key_path = overcloud_key_path.format(container=self.container)
|
||||||
|
if self._deployment_needs_local_cert(env, cert_path, key_path):
|
||||||
|
self._request_cert_if_necessary(env, cert_path, key_path)
|
||||||
|
parameters['SSLCertificate'] = self._get_local_file(cert_path)
|
||||||
|
parameters['SSLKey'] = self._get_local_file(key_path)
|
||||||
|
|
||||||
def _get_local_cacert(self, local_ca_path):
|
def _get_local_cacert(self, local_ca_path):
|
||||||
# Since the undercloud has TLS by default, we'll add the undercloud's
|
# Since the undercloud has TLS by default, we'll add the undercloud's
|
||||||
@ -223,9 +237,20 @@ class DeployStackAction(templates.ProcessTemplatesAction):
|
|||||||
except Exception:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def _get_local_file(self, path):
|
||||||
|
with open(path, 'rb') as openfile:
|
||||||
|
return openfile.read()
|
||||||
|
|
||||||
def _get_camap(self, env):
|
def _get_camap(self, env):
|
||||||
return env['parameter_defaults'].get('CAMap', {})
|
return env['parameter_defaults'].get('CAMap', {})
|
||||||
|
|
||||||
|
def _get_overcloud_tls_certificate(self, env):
|
||||||
|
cert_raw = env['parameter_defaults'].get('SSLCertificate', b'')
|
||||||
|
if hasattr(cert_raw, 'encode'):
|
||||||
|
return cert_raw.encode('ascii')
|
||||||
|
else:
|
||||||
|
return cert_raw
|
||||||
|
|
||||||
def _get_updated_camap_entry(self, entry_name, cacert, orig_camap):
|
def _get_updated_camap_entry(self, entry_name, cacert, orig_camap):
|
||||||
ca_map_entry = {
|
ca_map_entry = {
|
||||||
entry_name: {
|
entry_name: {
|
||||||
@ -235,6 +260,68 @@ class DeployStackAction(templates.ProcessTemplatesAction):
|
|||||||
orig_camap.update(ca_map_entry)
|
orig_camap.update(ca_map_entry)
|
||||||
return orig_camap
|
return orig_camap
|
||||||
|
|
||||||
|
def _cert_is_from_local_issuer(self, cert):
|
||||||
|
for attribute in cert.issuer:
|
||||||
|
# '2.5.4.3' is the OID of the certificate issuer's CommonName or CN
|
||||||
|
# 'Local Signing Authority' is the default CA name that certmonger
|
||||||
|
# uses for the local CA
|
||||||
|
if (attribute.oid.dotted_string == '2.5.4.3' and
|
||||||
|
attribute.value == 'Local Signing Authority'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _deployment_needs_local_cert(self, env, cert_path, key_path):
|
||||||
|
overcloud_cert_bytes = self._get_overcloud_tls_certificate(env)
|
||||||
|
overcloud_certmonger = env['parameter_defaults'].get(
|
||||||
|
'PublicSSLCertificateAutogenerated', False)
|
||||||
|
enable_tls_flag = env['parameter_defaults'].get(
|
||||||
|
'EnablePublicTLS', True)
|
||||||
|
if overcloud_cert_bytes:
|
||||||
|
overcloud_cert = x509.load_pem_x509_certificate(
|
||||||
|
overcloud_cert_bytes, default_backend())
|
||||||
|
if not self._cert_is_from_local_issuer(overcloud_cert):
|
||||||
|
return False
|
||||||
|
elif overcloud_certmonger or not enable_tls_flag:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _request_cert_if_necessary(self, env, cert_path, key_path):
|
||||||
|
overcloud_fqdn = env['parameter_defaults'].get(
|
||||||
|
'CloudName', 'overcloud.localdomain')
|
||||||
|
if self._local_cert_request_present():
|
||||||
|
# Even if certmonger is tracking the request, the user
|
||||||
|
# might have deleted the cert file, so we resubmit the request.
|
||||||
|
if not os.path.isfile(cert_path):
|
||||||
|
self._request_local_cert(
|
||||||
|
overcloud_fqdn,
|
||||||
|
resubmit=True)
|
||||||
|
if not os.path.isfile(key_path):
|
||||||
|
raise RuntimeError(
|
||||||
|
"The key \"{0}\" is not present, you'll need to "
|
||||||
|
"recreate the certificate manually.".format(key_path))
|
||||||
|
else:
|
||||||
|
self._request_local_cert(overcloud_fqdn)
|
||||||
|
|
||||||
|
def _request_local_cert(self, overcloud_fqdn, resubmit=False):
|
||||||
|
action = 'request' if not resubmit else 'resubmit'
|
||||||
|
return processutils.execute(
|
||||||
|
'/usr/bin/sudo',
|
||||||
|
'/usr/bin/tripleo-overcloud-cert',
|
||||||
|
action,
|
||||||
|
self.container,
|
||||||
|
overcloud_fqdn)
|
||||||
|
|
||||||
|
def _local_cert_request_present(self):
|
||||||
|
try:
|
||||||
|
processutils.execute(
|
||||||
|
'/usr/bin/sudo',
|
||||||
|
'/usr/bin/tripleo-overcloud-cert',
|
||||||
|
'query',
|
||||||
|
self.container)
|
||||||
|
return True
|
||||||
|
except processutils.ProcessExecutionError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class OvercloudRcAction(base.TripleOAction):
|
class OvercloudRcAction(base.TripleOAction):
|
||||||
"""Generate the overcloudrc and overcloudrc.v3 for a plan
|
"""Generate the overcloudrc and overcloudrc.v3 for a plan
|
||||||
|
@ -57,6 +57,10 @@ DEFAULT_VALIDATIONS_PATH = \
|
|||||||
# The path to the local CA certificate installed on the undercloud
|
# The path to the local CA certificate installed on the undercloud
|
||||||
LOCAL_CACERT_PATH = '/etc/pki/ca-trust/source/anchors/cm-local-ca.pem'
|
LOCAL_CACERT_PATH = '/etc/pki/ca-trust/source/anchors/cm-local-ca.pem'
|
||||||
|
|
||||||
|
# The path to the locally generated overcloud certificate and key
|
||||||
|
OVERCLOUD_CERT_PATH = '/etc/pki/tls/certs/overcloud-{container}-cert.pem'
|
||||||
|
OVERCLOUD_KEY_PATH = '/etc/pki/tls/private/overcloud-{container}-key.pem'
|
||||||
|
|
||||||
# TRIPLEO_META_USAGE_KEY is inserted into metadata for containers created in
|
# TRIPLEO_META_USAGE_KEY is inserted into metadata for containers created in
|
||||||
# Swift via SwiftPlanStorageBackend to identify them from other containers
|
# Swift via SwiftPlanStorageBackend to identify them from other containers
|
||||||
TRIPLEO_META_USAGE_KEY = 'x-container-meta-usage-tripleo'
|
TRIPLEO_META_USAGE_KEY = 'x-container-meta-usage-tripleo'
|
||||||
|
@ -12,6 +12,14 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography import x509
|
||||||
|
from cryptography.x509.oid import NameOID
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
import mock
|
import mock
|
||||||
import tempfile
|
import tempfile
|
||||||
import yaml
|
import yaml
|
||||||
@ -362,7 +370,44 @@ class DeployStackActionTest(base.TestCase):
|
|||||||
"overcloud-swift-rings", "swift-rings.tar.gz",
|
"overcloud-swift-rings", "swift-rings.tar.gz",
|
||||||
"overcloud-swift-rings/swift-rings.tar.gz-%d" % 1473366264)
|
"overcloud-swift-rings/swift-rings.tar.gz-%d" % 1473366264)
|
||||||
|
|
||||||
def test_set_tls_parameters_no_ca_found(self):
|
|
||||||
|
class DeployStackActionSetTLSParametersTest(base.TestCase):
|
||||||
|
|
||||||
|
def get_self_signed_certificate_and_private_key(self):
|
||||||
|
private_key = rsa.generate_private_key(public_exponent=3,
|
||||||
|
key_size=1024,
|
||||||
|
backend=default_backend())
|
||||||
|
issuer = x509.Name([
|
||||||
|
x509.NameAttribute(NameOID.COUNTRY_NAME, u"FI"),
|
||||||
|
x509.NameAttribute(NameOID.LOCALITY_NAME, u"Helsinki"),
|
||||||
|
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"Some Company"),
|
||||||
|
x509.NameAttribute(NameOID.COMMON_NAME, u"Test Certificate"),
|
||||||
|
])
|
||||||
|
cert_builder = x509.CertificateBuilder(
|
||||||
|
issuer_name=issuer, subject_name=issuer,
|
||||||
|
public_key=private_key.public_key(),
|
||||||
|
serial_number=x509.random_serial_number(),
|
||||||
|
not_valid_before=datetime.utcnow(),
|
||||||
|
not_valid_after=datetime.utcnow() + timedelta(days=10)
|
||||||
|
)
|
||||||
|
cert = cert_builder.sign(private_key,
|
||||||
|
hashes.SHA256(),
|
||||||
|
default_backend())
|
||||||
|
cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM)
|
||||||
|
key_pem = private_key.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
|
encryption_algorithm=serialization.NoEncryption())
|
||||||
|
return cert_pem, key_pem
|
||||||
|
|
||||||
|
def create_temp_file(self, content):
|
||||||
|
temp_file = tempfile.NamedTemporaryFile()
|
||||||
|
temp_file.write(content)
|
||||||
|
temp_file.flush()
|
||||||
|
self.addCleanup(temp_file.close)
|
||||||
|
return temp_file.name
|
||||||
|
|
||||||
|
def test_no_ca_found(self):
|
||||||
action = deployment.DeployStackAction(1, 'overcloud',
|
action = deployment.DeployStackAction(1, 'overcloud',
|
||||||
skip_deploy_identifier=True)
|
skip_deploy_identifier=True)
|
||||||
my_params = {}
|
my_params = {}
|
||||||
@ -371,49 +416,58 @@ class DeployStackActionTest(base.TestCase):
|
|||||||
local_ca_path='/tmp/my-unexistent-file.txt')
|
local_ca_path='/tmp/my-unexistent-file.txt')
|
||||||
self.assertEqual(my_params, {})
|
self.assertEqual(my_params, {})
|
||||||
|
|
||||||
def test_set_tls_parameters_ca_found_no_camap_provided(self):
|
@mock.patch('oslo_concurrency.processutils.execute')
|
||||||
|
def test_ca_found_no_camap_provided(self, mock_execute):
|
||||||
action = deployment.DeployStackAction(1, 'overcloud',
|
action = deployment.DeployStackAction(1, 'overcloud',
|
||||||
skip_deploy_identifier=True)
|
skip_deploy_identifier=True)
|
||||||
|
# Write test data
|
||||||
my_params = {}
|
my_params = {}
|
||||||
my_env = {'parameter_defaults': {}}
|
my_env = {'parameter_defaults': {}}
|
||||||
with tempfile.NamedTemporaryFile() as ca_file:
|
cert_pem, _ = self.get_self_signed_certificate_and_private_key()
|
||||||
# Write test data
|
ca_file_path = self.create_temp_file(cert_pem)
|
||||||
ca_file.write(b'FAKE CA CERT')
|
overcloud_cert_path = self.create_temp_file(b'FAKE OVERCLOUD CERT')
|
||||||
ca_file.flush()
|
overcloud_key_path = self.create_temp_file(b'FAKE OVERCLOUD KEY')
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
action.set_tls_parameters(parameters=my_params, env=my_env,
|
action.set_tls_parameters(parameters=my_params, env=my_env,
|
||||||
local_ca_path=ca_file.name)
|
local_ca_path=ca_file_path,
|
||||||
self.assertIn('CAMap', my_params)
|
overcloud_cert_path=overcloud_cert_path,
|
||||||
self.assertIn('undercloud-ca', my_params['CAMap'])
|
overcloud_key_path=overcloud_key_path)
|
||||||
self.assertIn('content', my_params['CAMap']['undercloud-ca'])
|
self.assertIn('CAMap', my_params)
|
||||||
self.assertEqual(b'FAKE CA CERT',
|
self.assertIn('undercloud-ca', my_params['CAMap'])
|
||||||
my_params['CAMap']['undercloud-ca']['content'])
|
self.assertIn('content', my_params['CAMap']['undercloud-ca'])
|
||||||
|
self.assertEqual(cert_pem,
|
||||||
|
my_params['CAMap']['undercloud-ca']['content'])
|
||||||
|
|
||||||
def test_set_tls_parameters_ca_found_camap_provided(self):
|
@mock.patch('oslo_concurrency.processutils.execute')
|
||||||
|
def test_ca_found_camap_provided(self, mock_execute):
|
||||||
action = deployment.DeployStackAction(1, 'overcloud',
|
action = deployment.DeployStackAction(1, 'overcloud',
|
||||||
skip_deploy_identifier=True)
|
skip_deploy_identifier=True)
|
||||||
|
# Write test data
|
||||||
|
undercloud_pem, _ = self.get_self_signed_certificate_and_private_key()
|
||||||
|
overcloud_pem, _ = self.get_self_signed_certificate_and_private_key()
|
||||||
my_params = {}
|
my_params = {}
|
||||||
my_env = {
|
my_env = {
|
||||||
'parameter_defaults': {
|
'parameter_defaults': {
|
||||||
'CAMap': {'overcloud-ca': {'content': b'ANOTER FAKE CERT'}}}}
|
'CAMap': {'overcloud-ca': {'content': overcloud_pem}}}}
|
||||||
with tempfile.NamedTemporaryFile() as ca_file:
|
ca_file_path = self.create_temp_file(undercloud_pem)
|
||||||
# Write test data
|
overcloud_cert_path = self.create_temp_file(b'FAKE OVERCLOUD CERT')
|
||||||
ca_file.write(b'FAKE CA CERT')
|
overcloud_key_path = self.create_temp_file(b'FAKE OVERCLOUD KEY')
|
||||||
ca_file.flush()
|
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
action.set_tls_parameters(parameters=my_params, env=my_env,
|
action.set_tls_parameters(parameters=my_params, env=my_env,
|
||||||
local_ca_path=ca_file.name)
|
local_ca_path=ca_file_path,
|
||||||
self.assertIn('CAMap', my_params)
|
overcloud_cert_path=overcloud_cert_path,
|
||||||
self.assertIn('undercloud-ca', my_params['CAMap'])
|
overcloud_key_path=overcloud_key_path)
|
||||||
self.assertIn('content', my_params['CAMap']['undercloud-ca'])
|
self.assertIn('CAMap', my_params)
|
||||||
self.assertEqual(b'FAKE CA CERT',
|
self.assertIn('undercloud-ca', my_params['CAMap'])
|
||||||
my_params['CAMap']['undercloud-ca']['content'])
|
self.assertIn('content', my_params['CAMap']['undercloud-ca'])
|
||||||
self.assertIn('overcloud-ca', my_params['CAMap'])
|
self.assertEqual(undercloud_pem,
|
||||||
self.assertIn('content', my_params['CAMap']['overcloud-ca'])
|
my_params['CAMap']['undercloud-ca']['content'])
|
||||||
self.assertEqual(b'ANOTER FAKE CERT',
|
self.assertIn('overcloud-ca', my_params['CAMap'])
|
||||||
my_params['CAMap']['overcloud-ca']['content'])
|
self.assertIn('content', my_params['CAMap']['overcloud-ca'])
|
||||||
|
self.assertEqual(overcloud_pem,
|
||||||
|
my_params['CAMap']['overcloud-ca']['content'])
|
||||||
|
|
||||||
|
|
||||||
class OvercloudRcActionTestCase(base.TestCase):
|
class OvercloudRcActionTestCase(base.TestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user