Merge "Adds network/cidr mapping into a new service property"
[apex-tripleo-heat-templates.git] / tools / yaml-validate.py
index 396998a..66e38ef 100755 (executable)
@@ -18,7 +18,7 @@ import yaml
 
 
 required_params = ['EndpointMap', 'ServiceNetMap', 'DefaultPasswords',
-                   'RoleName', 'RoleParameters']
+                   'RoleName', 'RoleParameters', 'ServiceData']
 
 # NOTE(bnemec): The duplication in this list is intentional.  For the
 # transition to generated environments we have two copies of these files,
@@ -38,7 +38,7 @@ OPTIONAL_DOCKER_SECTIONS = ['docker_puppet_tasks', 'upgrade_tasks',
                             'metadata_settings', 'kolla_config']
 REQUIRED_DOCKER_PUPPET_CONFIG_SECTIONS = ['config_volume', 'step_config',
                                           'config_image']
-OPTIONAL_DOCKER_PUPPET_CONFIG_SECTIONS = [ 'puppet_tags' ]
+OPTIONAL_DOCKER_PUPPET_CONFIG_SECTIONS = [ 'puppet_tags', 'volumes' ]
 # Mapping of parameter names to a list of the fields we should _not_ enforce
 # consistency across files on.  This should only contain parameters whose
 # definition we cannot change for backwards compatibility reasons.  New
@@ -53,12 +53,22 @@ PARAMETER_DEFINITION_EXCLUSIONS = {'ManagementNetCidr': ['default'],
                                    'StorageMgmtAllocationPools': ['default'],
                                    }
 
+PREFERRED_CAMEL_CASE = {
+    'ec2api': 'Ec2Api',
+    'haproxy': 'HAProxy',
+}
+
 
 def exit_usage():
     print('Usage %s <yaml file or directory>' % sys.argv[0])
     sys.exit(1)
 
 
+def to_camel_case(string):
+    return PREFERRED_CAMEL_CASE.get(string, ''.join(s.capitalize() or '_' for
+                                                    s in string.split('_')))
+
+
 def get_base_endpoint_map(filename):
     try:
         tpl = yaml.load(open(filename).read())
@@ -183,6 +193,30 @@ def validate_docker_service(filename, tpl):
                         % (key, filename))
                   return 1
 
+            config_volume = puppet_config.get('config_volume')
+            expected_config_image_parameter = "Docker%sConfigImage" % to_camel_case(config_volume)
+            if config_volume and not expected_config_image_parameter in tpl.get('parameters', []):
+                print('ERROR: Missing %s heat parameter for %s config_volume.'
+                      % (expected_config_image_parameter, config_volume))
+                return 1
+
+        if 'docker_config' in role_data:
+            docker_config = role_data['docker_config']
+            for _, step in docker_config.items():
+                for _, container in step.items():
+                    if not isinstance(container, dict):
+                        # NOTE(mandre) this skips everything that is not a dict
+                        # so we may ignore some containers definitions if they
+                        # are in a map_merge for example
+                        continue
+                    command = container.get('command', '')
+                    if isinstance(command, list):
+                        command = ' '.join(map(str, command))
+                    if 'bootstrap_host_exec' in command \
+                            and container.get('user') != 'root':
+                      print('ERROR: bootstrap_host_exec needs to run as the root user.')
+                      return 1
+
     if 'parameters' in tpl:
         for param in required_params:
             if param not in tpl['parameters']:
@@ -303,6 +337,8 @@ param_map = {}
 for base_path in path_args:
     if os.path.isdir(base_path):
         for subdir, dirs, files in os.walk(base_path):
+            if '.tox' in dirs:
+                dirs.remove('.tox')
             for f in files:
                 if f.endswith('.yaml') and not f.endswith('.j2.yaml'):
                     file_path = os.path.join(subdir, f)