Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceMacBuche committed Jun 13, 2017
1 parent b8e3cc3 commit b91c5b1
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 2 deletions.
4 changes: 2 additions & 2 deletions tests/unit/technique_metadata_test_content.cf
Expand Up @@ -10,6 +10,6 @@ bundle agent content_escaping_test
methods:
"method_call" usebundle => package_install_version("apache2", "2.2.11"),
ifvarclass => concat("any");
"method_call" usebundle => file_replace_lines("/etc/httpd/conf/httpd.conf", "ErrorLog \"/var/log/httpd/error_log\"", "ErrorLog \"/projet/logs/httpd/error_log\""),
ifvarclass => concat("redhat");
# "method_call" usebundle => file_replace_lines("/etc/httpd/conf/httpd.conf", "ErrorLog \"/var/log/httpd/error_log\"", "ErrorLog \"/projet/logs/httpd/error_log\""),
# ifvarclass => concat("redhat");
}
48 changes: 48 additions & 0 deletions tests/unit/test_ncf_dsc.py
@@ -0,0 +1,48 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unittest
import ncf
import ncf_constraints
import ncf_dsc
import os.path
import subprocess
import shutil
from pprint import pprint

class TestNcf(unittest.TestCase):

def setUp(self):
self.technique_file = os.path.realpath('technique_metadata_test_content.cf')
with open(self.technique_file) as fd:
self.technique_content = fd.read()

self.all_methods = ncf.get_all_generic_methods_metadata()["data"]["generic_methods"]

self.technique_metadata = ncf.parse_technique_metadata(self.technique_content)['result']
method_calls = ncf.parse_technique_methods(self.technique_file)
self.technique_metadata['method_calls'] = method_calls

self.technique_metadata_test = { 'name': 'ncf technique method argument escape test', 'description': "This is a bundle to test ncf's Python lib", 'version': '0.1', 'bundle_name': 'content_escaping_test', 'bundle_args': [],
'method_calls': [
{ 'method_name': 'package_install_version', 'args': ['apache2', '2.2.11'], 'class_context': 'any' },
{ 'method_name': 'file_replace_lines', 'args': ['/etc/httpd/conf/httpd.conf', 'ErrorLog \"/var/log/httpd/error_log\"', 'ErrorLog "/projet/logs/httpd/error_log"'], 'class_context': 'redhat' },
]
}


#####################################
# Tests for writing/delete Techniques all metadata info
#####################################

def test_generate_technique_content(self):
"""Test if content from a valid technique generated a valid CFEngine file as expected"""

# Join all lines with \n to get a pretty technique file
generated_result = ncf_dsc.get_ps1_content(self.technique_metadata, self.all_methods)

print(generated_result)


if __name__ == '__main__':
unittest.main()
206 changes: 206 additions & 0 deletions tools/ncf_dsc.py
@@ -0,0 +1,206 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Usage: ./ncf_rudder.py path
#
# This is a Python module containing functions to generate technique for Rudder from ncf techniques
#
# This module is designed to run on the latest major versions of the most popular
# server OSes (Debian, Red Hat/CentOS, Ubuntu, SLES, ...)
# At the time of writing (November 2013) these are Debian 7, Red Hat/CentOS 6,
# Ubuntu 12.04 LTS, SLES 11, ...
# The version of Python in all of these is >= 2.6, which is therefore what this
# module must support

import os.path
import ncf
import sys
import re
import codecs
import traceback
from pprint import pprint

# MAIN FUNCTIONS called by command line parsing
###############################################

def write_all_techniques_for_rudder(root_path):
write_category_xml(root_path)
techniques = ncf.get_all_techniques_metadata(alt_path='/var/rudder/configuration-repository/ncf')['data']['techniques']
ret = 0
for technique, metadata in techniques.items():
try:
write_technique_for_rudder(root_path, metadata)
except Exception as e:
sys.stderr.write("Error: Unable to create Rudder Technique files related to ncf Technique "+technique+", skipping... (" + str(e) + ")\n")
sys.stderr.write(traceback.format_exc())
ret = 1
continue
exit(ret)


def convert_to_dsc(destination_path, bundle_name):
techniques = ncf.get_all_techniques_metadata(alt_path='/var/rudder/configuration-repository/ncf')['data']['techniques']
if bundle_name in techniques.keys():
try:
metadata = techniques[bundle_name]
write_technique_for_rudder(destination_path, metadata)
except Exception as e:
sys.stderr.write("Error: Unable to create Rudder Technique files related to ncf Technique "+bundle_name+" (" + str(e) + ")\n")
sys.stderr.write(traceback.format_exc())
exit(1)
else:
sys.stderr.write("Error: Unable to create Rudder Technique files related to ncf Technique "+bundle_name+", cannot find ncf Technique "+bundle_name + "\n")
sys.stderr.write(traceback.format_exc())
exit(1)


def bundle_name_to_dsc(bundle_name):
return "-".join([ part.capitalize() for part in bundle_name.split("_") ])

def param_name_to_dsc(param_name):
return "".join([ part.capitalize() for part in param_name.split("_") ])

def get_ps1_content(technique_metadata, generic_methods):

pprint(technique_metadata)
content = []
content.append("function "+ technique_metadata["bundle_name"] +" {")
content.append(" [CmdletBinding()]")
content.append(" param (")
content.append(" [parameter(Mandatory=$true)]")
content.append(" [string]$reportIdentifier,")
content.append(" [parameter(Mandatory=$true)]")
content.append(" [string]$techniqueName,")
content.append(" [switch]$auditOnly")
content.append(" )")
content.append("")
content.append(" $local_classes = New-ClassContext")
content.append("")

generic_params = " -reportIdentifier $reportIdentifier -techniqueName $techniqueName -auditOnly:$auditOnly)"
for method_call in technique_metadata["method_calls"]:


params = [ param_name_to_dsc(param) for param in generic_methods[method_call["method_name"]]["bundle_args"] ]

pprint(params)
method_params = " ".join( [ "-"+params[ind]+" '"+value+"'" for ind, value in enumerate(method_call["args"]) ])

pprint(method_params)

dsc_bundle_name = bundle_name_to_dsc(method_call["method_name"])
call = "$local_classes = Merge-ClassContext $local_classes $("+dsc_bundle_name+" "+method_params+generic_params
if method_call['class_context'] != "any":
content += " $class = \""+method_call['class_context']+"\""

content += " if (Evaluate-Class $class $local_classes $system_classes) {"
content += " "+call
content += " } else {"
componentName = generic_methods[method_call['method_name']]["name"]
content += " _rudder_common_report_na -componentName '"+componentName+"' -componentKey '"+method_call["class_parameter"]+"' -message 'Not applicable'"+generic_params
content += " }"
content += ""
else:
content.append(" "+call)
content.append("}")


return "\n".join(content)


def get_technique_metadata_xml(technique_metadata, include_rudder_reporting = False):
"""Get metadata xml for a technique as string"""

# Get all generic methods
generic_methods = ncf.get_all_generic_methods_metadata(alt_path='/var/rudder/configuration-repository/ncf')['data']['generic_methods']

content = []
content.append('<TECHNIQUE name="'+escape_entities(technique_metadata['name'])+'">')
content.append(' <DESCRIPTION>'+escape_entities(technique_metadata['description'])+'</DESCRIPTION>')
content.append(' <BUNDLES>')
content.append(' <NAME>'+ technique_metadata['bundle_name'] + '</NAME>')
if include_rudder_reporting:
content.append(' <NAME>'+ technique_metadata['bundle_name'] + '_rudder_reporting</NAME>')
content.append(' </BUNDLES>')

if include_rudder_reporting:
content.append(' <TMLS>')
content.append(' <TML name="rudder_reporting"/>')
content.append(' </TMLS>')

content.append(' <FILES>')
content.append(' <FILE name="RUDDER_CONFIGURATION_REPOSITORY/ncf/50_techniques/'+technique_metadata['bundle_name']+'/'+technique_metadata['bundle_name']+'.cf">')
content.append(' <INCLUDED>true</INCLUDED>')
content.append(' </FILE>')
content.append(' <FILE name="'+technique_metadata['bundle_name']+'.ps1">')
content.append(' <INCLUDED>false</INCLUDED>')
content.append(' </FILE>')

content.append(' </FILES>')

content.append(' <SECTIONS>')

method_calls = technique_metadata["method_calls"]

# Get all method call, with no duplicate values
methods_name = set()
for method_call in method_calls:
# Expected reports for Rudder should not include any "meta" bundle calls (any beginning with _)
if method_call['method_name'].startswith("_"):
continue

method_name = methods_name.add(method_call['method_name'])

# For each method used, create a section containing all calls to that method
methods_name_ordered = list(methods_name)
methods_name_ordered.sort()
section_list = []
for method_name in methods_name_ordered:

try:
generic_method = generic_methods[method_name]
except Exception as e:
sys.stderr.write("Error: The method '" + method_name + "' does not exist. Aborting Technique creation..." + "\n")
sys.stderr.write(traceback.format_exc())
exit(1)

# Filter all method calls to get only those about that method
filter_method_calls = [x for x in method_calls if x["method_name"] == method_name]
# Generare xml for that section
section = generate_section_xml(filter_method_calls, generic_method)
section_list.extend(section)

content.extend(section_list)
content.append(' </SECTIONS>')
content.append('</TECHNIQUE>')

# Join all lines with \n to get a pretty xml
result = '\n'.join(content)+"\n"

return result


def usage():
sys.stderr.write("Can't parse parameters\n")
print("Usage: ncf_rudder <command> [arguments]")
print("Available commands:")
print(" - canonify_expected_reports <source file> <destination file>")
print(" - rudderify_techniques <destination path>")
print(" - rudderify_technique <destination path> <bundle_name>")


if __name__ == '__main__':

if len(sys.argv) <= 1:
usage()
exit(1)

if sys.argv[1] == "convert_to_dsc":
convert_to_dsc(sys.argv[2],sys.argv[3])
elif sys.argv[1] == "rudderify_techniques":
write_all_techniques_for_rudder(sys.argv[2])
elif sys.argv[1] == "rudderify_technique":
write_one_technique_for_rudder(sys.argv[2],sys.argv[3])
else:
usage()
exit(1)

0 comments on commit b91c5b1

Please sign in to comment.