return cast(FuncT, inner)
+class YamlLiteralString(str):
+ """
+ Class used as marker for yaml representer to properly format
+ multi-line strings for yaml export
+ """
+ @staticmethod
+ def represent_as_literal(dumper: 'yaml.SafeDumper', data: str) -> Any:
+ return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
+
+
+yaml.add_representer(YamlLiteralString, YamlLiteralString.represent_as_literal)
+
+
class HostPlacementSpec(NamedTuple):
hostname: str
network: str
@staticmethod
def yaml_representer(dumper: 'yaml.SafeDumper', data: 'ServiceSpec') -> Any:
- return dumper.represent_dict(cast(Mapping, data.to_json().items()))
+ json_data = data.to_json()
+ spec = json_data.get('spec', {})
+
+ # Marking multi-line strings with the YamlLiteralString class
+ for key, value in spec.items():
+ if isinstance(value, str) and '\n' in value:
+ spec[key] = YamlLiteralString(value)
+
+ return dumper.represent_dict(cast(Mapping, json_data.items()))
yaml.add_representer(ServiceSpec, ServiceSpec.yaml_representer)
PrometheusSpec,
RGWSpec,
ServiceSpec,
+ YamlLiteralString,
)
from ceph.deployment.drive_group import DriveGroupSpec
from ceph.deployment.hostspec import SpecValidationError
spec_section = j.get('spec', {})
assert 'termination_grace_period_seconds' not in spec_section
+
+def test_yaml_literal_string_class_represents_multiline_strings_as_literal():
+ multiline_string = "test1\ntest2\n"
+ dumped = yaml.dump(YamlLiteralString(multiline_string))
+
+ assert dumped.startswith('|')
+
+def test_yaml_representer_can_handle_multiline_strings_for_export():
+ spec_data = """
+service_type: iscsi
+service_id: iscsi
+placement:
+ label: iscsi
+spec:
+ pool: testpool
+ ssl_cert: |
+ -----BEGIN CERTIFICATE-----
+ FILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLER
+ FILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLER
+ -----END CERTIFICATE-----
+ ssl_key: |
+ -----BEGIN PRIVATE KEY-----
+ FILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLER
+ FILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLERFILLER
+ -----END PRIVATE KEY-----
+"""
+
+ data = yaml.safe_load(spec_data)
+ spec_obj = ServiceSpec.from_json(data)
+
+ dumped = yaml.dump(spec_obj, default_flow_style=False)
+
+ assert 'ssl_cert: |' in dumped
+ assert 'ssl_key: |' in dumped