def generate_deploy(self, commands, app_name, service_name, docker_links, env, config): if self._tmp_dir_ is None: raise DMakeException( 'Sanity check failed: it seems the build step has been skipped: _tmp_dir_ is null.' ) if self.deploy_name is not None: app_name = self.deploy_name else: app_name = "dp-%s-%s" % (app_name, service_name) links = [] for link_name in config.docker_links_names: if link_name not in docker_links: raise DMakeException("Unknown link name: '%s'" % link_name) links.append(docker_links[link_name]) for stage in self.stages: branches = stage.branches if common.branch not in branches and '*' not in branches: continue env = copy.deepcopy(env) for var, value in stage.env.items(): env[var] = value os.environ[var] = value generate_dockerfile(commands, self._tmp_dir_, env) stage.aws_beanstalk._serialize_(commands, self._tmp_dir_, app_name, links, config) stage.ssh._serialize_(commands, self._tmp_dir_, app_name, links, config)
def load_deepomake_file(loaded_files, blacklist, service_providers, service_dependencies, file): if file in loaded_files: return if file in blacklist: return # Load YAML and check version try: with open(file, 'r') as stream: data = yaml.load(stream) except yaml.parser.ParserError as e: raise DMakeException(str(e)) if 'dmake_version' not in data: raise DMakeException("Missing field 'dmake_version' in %s" % file) version = str(data['dmake_version']) if version not in ['0.1']: raise DMakeException("Incorrect version '%s'" % str(data['dmake_version'])) # Load appropriate version (TODO: versionning) if version == '0.1': deepomake = DeepoMakeFile(file, data) loaded_files[file] = deepomake # Blacklist should be on child file because they are loaded this way for bl in deepomake.blacklist: blacklist.append(bl) for link in deepomake.docker_links: add_service_provider( service_providers, 'links/%s/%s' % (deepomake.get_app_name(), link.link_name), file) # Unroll docker image references if common.is_string(deepomake.docker): ref = deepomake.docker load_deepomake_file(loaded_files, blacklist, service_providers, service_dependencies, ref) deepomake.__fields__['docker'] = loaded_files[ref].docker else: if common.is_string(deepomake.docker.root_image): ref = deepomake.docker.root_image load_deepomake_file(loaded_files, blacklist, service_providers, service_dependencies, ref) deepomake.docker.__fields__['root_image'] = loaded_files[ ref].docker.get_docker_base_image_name_tag() else: deepomake.docker.__fields__[ 'root_image'] = deepomake.docker.root_image.full_name() # If a base image is declared root_image = deepomake.docker.root_image base_image = deepomake.docker.get_docker_base_image_name_tag() if root_image != base_image: add_service_provider(service_providers, base_image, file) service_dependencies[('base', base_image)] = [('base', root_image)]
def check_cmd(args, required, optional=[]): for a in required: if a not in args: raise DMakeException("%s is required for command %s" % (a, cmd)) for a in args: if a not in required and a not in optional: raise DMakeException("Unexpected argument %s for command %s" % (a, cmd))
def _serialize_(self, commands, tmp_dir, app_name, docker_links, config): if not self.has_value(): return for port in config.ports: if port.container_port != port.host_port: raise DMakeException( "AWS Elastic Beanstalk only supports ports binding which are the same in the container and the host." ) ports = [{ "ContainerPort": ports.container_port } for ports in config.ports] volumes = [ { "HostDirectory": volume.host_volume, "ContainerDirectory": volume.container_volume } for volume in config.volumes if volume.host_volume != "/var/log/deepomatic" # Cannot specify a volume both in logging and mounting ] if config.pre_deploy_script != "" or \ config.mid_deploy_script != "" or \ config.post_deploy_script != "": raise DMakeException( "Pre/Mid/Post-Deploy scripts for AWS is not supported yet.") if len(config.docker_opts) > 0: raise DMakeException( "Docker options for AWS is not supported yet.") # Generate Dockerrun.aws.json data = { "AWSEBDockerrunVersion": "1", # "Authentication": { # "Bucket": "my-bucket", # "Key": "mydockercfg" # }, # "Image": { # "Name": "quay.io/johndoe/private-image", # "Update": "true" # }, "Ports": ports, "Volumes": volumes, "Logging": "/var/log/deepomatic" } with open(os.path.join(tmp_dir, "Dockerrun.aws.json"), 'w') as dockerrun: json.dump(data, dockerrun) common.run_shell_command( 'deepomake_replace_vars %s %s' % (self.options, os.path.join(tmp_dir, 'options.txt'))) append_command(commands, 'sh', shell='deepomake_deploy_aws_eb "%s" "%s" "%s" "%s"' % (tmp_dir, app_name, self.region, self.stack))
def __init__(self, file, data): super(DeepoMakeFile, self).__init__() self.__path__ = os.path.join(os.path.dirname(file), '') try: path = os.path.join(os.path.dirname(file), '') self._validate_(path, data) except ValidationError as e: raise DMakeException(("Error in %s:\n" % file) + str(e)) if self.env.__has_value__: env = copy.deepcopy(self.env.default) if common.branch in self.env.branches: for var, value in self.env.branches[common.branch].items(): env[var] = value env_field = FieldSerializer("dict", child="string") env_field._validate_(self.__path__, env) self.__fields__['env'] = env_field else: self.__fields__['env'] = {} self.env_file = None self.docker_cmd = None self.docker_services_image = None
def activate_file(loaded_files, service_providers, service_dependencies, command, file): file_deps = {'build_tests': 'base', 'build_service': 'base'} deepomake = loaded_files[file] if command == 'base': base_image = deepomake.docker.get_docker_base_image_name_tag() return [('base', base_image)] elif command in file_deps: node = (command, file) if node not in service_dependencies: service_dependencies[node] = activate_file(loaded_files, service_providers, service_dependencies, file_deps[command], file) return [node] elif command in ['test', 'run', 'deploy']: nodes = [] for service in deepomake.get_services(): full_service_name = "%s/%s" % (deepomake.app_name, service.service_name) nodes += activate_service(loaded_files, service_providers, service_dependencies, command, full_service_name) return nodes else: raise DMakeException('Unexpected command %s' % command)
def generate_command_bash(file, cmds): file.write('set -e\n') for cmd, kwargs in cmds: if cmd == "stage": file.write("echo %s\n" % kwargs['name']) elif cmd == "sh": commands = kwargs['shell'] if common.is_string(commands): commands = [commands] for c in commands: file.write("%s\n" % c) elif cmd == "read_sh": file.write("export %s=`%s`\n" % (kwargs['var'], kwargs['shell'])) if kwargs['fail_if_empty']: file.write("if [ -z \"${%s}\" ]; then exit 1; fi\n" % kwargs['var']) elif cmd == "env": file.write('export %s="%s"\n' % (kwargs['var'], kwargs['value'].replace('"', '\\"'))) elif cmd == "git_tag": file.write('git tag --force %s\n' % kwargs['tag']) file.write('git push --force --tags || echo %s\n' % tag_push_error_msg) elif cmd == "junit": pass # Should be configured with GUI elif cmd == "cobertura": pass # Should be configured with GUI elif cmd == "publishHTML": pass # Should be configured with GUI elif cmd == "build": pass # Should be configured with GUI else: raise DMakeException("Unknown command %s" % cmd)
def generate_example(self): if self.example is not None: return self.example elif self.default: return self.default value = None for t in self.data_type: if isinstance(t, YAML2PipelineSerializer) or isinstance( t, FieldSerializer): return t.generate_example() elif t == "dict": value = {'any_key': self.child.generate_example()} elif t == "array": value = [self.child.generate_example()] elif value is None: if t == "int": value = "1" elif t == "path" or t == "dir": path_str = "path" if t == "path" else "directory" if self.child_path_only: value = "some/relative/%s/example" % path_str else: value = "some/%s/example" % path_str elif t == "string": value = "Some string" elif t == "bool": value = "true" else: raise DMakeException("Unknown type: %s" % str(t)) return value
def _serialize_(self, *args, **kwargs): if isinstance(self.value, list): for f in self.value: f._serialize_(*args, **kwargs) else: raise DMakeException( "Do not known how to serialize non array field")
def add_service_provider(service_providers, service, file, needs=None): if service in service_providers: if service_providers[service] != file: raise DMakeException( 'Service %s re-defined in %s. First defined in %s' % (service, file, service_providers[service])) else: service_providers[service] = (file, needs)
def default_value(self): value = {} for k, v in self.__fields__.items(): try: value[k] = v._default_() except ValidationError as e: raise DMakeException("Field '%s': %s" % (k, str(e))) return value
def generate_build(self, commands, path_dir, app_name, service_name, docker_base, env, config): if self._tmp_dir_ is not None: raise DMakeException('Build already generated') if config.docker_image.has_value(): self._tmp_dir_ = config.docker_image.generate_build( commands, path_dir, app_name, service_name, docker_base, env, config)
def sub_check(key, walked_nodes=[]): if key in tree_depth: return tree_depth[key] if key not in dependencies: return 0 walked_nodes = [key] + walked_nodes depth = 0 for dep in dependencies[key]: is_leaf[dep] = False if dep in walked_nodes: raise DMakeException( "Circular dependencies: %s" % ' -> '.join(reversed([dep] + walked_nodes))) depth = max(depth, 1 + sub_check(dep, walked_nodes)) tree_depth[key] = depth return depth
def __getattribute__(self, key): try: fields = object.__getattribute__(self, '__fields__') except AttributeError: return object.__getattribute__(self, key) has_data = object.__getattribute__(self, '__has_value__') if key in fields: if isinstance(fields[key], FieldSerializer): if has_data: return fields[key]._value_() else: raise DMakeException( "No data has been validated yet, cannot access field '%s'" % key) else: return fields[key] else: return object.__getattribute__(self, key)
def append_command(commands, cmd, prepend=False, **args): def check_cmd(args, required, optional=[]): for a in required: if a not in args: raise DMakeException("%s is required for command %s" % (a, cmd)) for a in args: if a not in required and a not in optional: raise DMakeException("Unexpected argument %s for command %s" % (a, cmd)) if cmd == "stage": check_cmd(args, ['name', 'concurrency']) elif cmd == "sh": check_cmd(args, ['shell']) elif cmd == "read_sh": check_cmd(args, ['var', 'shell'], optional=['fail_if_empty']) args['id'] = len(commands) if 'fail_if_empty' not in args: args['fail_if_empty'] = False elif cmd == "env": check_cmd(args, ['var', 'value']) elif cmd == "git_tag": check_cmd(args, ['tag']) elif cmd == "junit": check_cmd(args, ['report']) elif cmd == "cobertura": check_cmd(args, ['report']) elif cmd == "publishHTML": check_cmd(args, ['directory', 'index', 'title']) elif cmd == "build": check_cmd(args, ['job', 'parameters', 'propagate', 'wait']) else: raise DMakeException("Unknow command %s" % cmd) cmd = (cmd, args) if prepend: commands.insert(0, cmd) else: commands.append(cmd)
def make(root_dir, sub_dir, dmake_command, app, options): if 'DMAKE_TMP_DIR' in os.environ: del os.environ['DMAKE_TMP_DIR'] common.init(dmake_command, root_dir, options) if dmake_command == "stop": common.run_shell_command( "docker rm -f `docker ps -q -f name=%s.%s.%s`" % (app, common.branch, common.build_id)) return if dmake_command == "deploy" and common.is_local: r = common.read_input( "Carefull ! Are you sure you want to do that ? [Y/n] ") if r.lower() != 'y' and r != "": print('Aborting') sys.exit(0) # Format args auto_complete = False auto_completed_app = None if app is not None: n = len(app.split('/')) if n > 2: raise DMakeException( 'Cannot have more than one slash in the app name') auto_complete = n == 1 if auto_complete: auto_completed_app = None auto_complete_is_app = None else: auto_completed_app = app # Load build files build_files = load_deepomake_files_list() if len(build_files) == 0: raise DMakeException('No deepomake.yml file found !') # Sort by increasing length to make sure we load parent files first sorted(build_files, key=lambda file: len(file)) # Load all deepomake.yml files (except those blacklisted) blacklist = [] loaded_files = {} service_providers = {} service_dependencies = {} for file in build_files: load_deepomake_file(loaded_files, blacklist, service_providers, service_dependencies, file) # Remove black listed files for f in blacklist: if f in loaded_files: del loaded_files[f] # Register all apps and services in the repo docker_links = {} services = {} for file, deepomake in loaded_files.items(): app_name = deepomake.get_app_name() if app_name not in docker_links: docker_links[app_name] = {} if app_name not in services: services[app_name] = {} if auto_complete and app_name == app: if auto_completed_app is None: auto_completed_app = app app_services = services[app_name] for service in deepomake.get_services(): needs = [ "%s/%s" % (app_name, sa) for sa in service.needed_services ] full_service_name = "%s/%s" % (app_name, service.service_name) if service.service_name in app_services: raise DMakeException("Duplicated sub-app name: '%s'" % full_service_name) add_service_provider(service_providers, full_service_name, file, needs) app_services[service.service_name] = service if auto_complete and service.service_name == app: if auto_completed_app is None: auto_completed_app = full_service_name auto_complete_is_app = False else: raise DMakeException( "Ambigous app name '%s' is matching sub-app '%s' and %sapp '%s'" % (app, full_service_name, "" if auto_complete_is_app else "sub-", auto_completed_app)) app_links = docker_links[app_name] for link in deepomake.get_docker_links(): if link.link_name in app_links: raise DMakeException( "Duplicate link name '%s' for application '%s'. Link names must be unique inside each app." % (link.link_name, app_name)) app_links[link.link_name] = link if auto_complete and auto_completed_app is None: raise DMakeException( "Could not find any app or sub-app matching '%s'" % app) # Filter base images which are not provided for deps in service_dependencies.values(): to_delete = [] for i, dep in enumerate(deps): if dep[1] not in service_providers: to_delete.append(i) to_delete.reverse() for i in to_delete: del deps[i] is_app_only = auto_completed_app is None or auto_completed_app.find( '/') < 0 if dmake_command == "run" and is_app_only: common.options.dependencies = True if auto_completed_app is None: # Find file where changes have happened find_active_files(loaded_files, service_providers, service_dependencies, sub_dir, dmake_command) else: if is_app_only: # app only if dmake_command == 'shell': raise DMakeException("Could not find sub-app '%s'" % app) active_file = set() app_services = services[auto_completed_app] for service in app_services.values(): full_service_name = "%s/%s" % (auto_completed_app, service.service_name) file, _ = service_providers[full_service_name] active_file.add(file) for file in active_file: activate_file(loaded_files, service_providers, service_dependencies, dmake_command, file) else: activate_service(loaded_files, service_providers, service_dependencies, dmake_command, auto_completed_app) # check services circularity sorted_leaves = check_no_circular_dependencies(service_dependencies) sorted_leaves = filter(lambda a_b__c: a_b__c[0][0] == dmake_command, sorted_leaves) build_files_order = order_dependencies(service_dependencies, sorted_leaves) # Sort by order ordered_build_files = sorted(build_files_order.items(), key=lambda file_order: file_order[1]) # Separate into base / build / tests / deploy n = len(ordered_build_files) base = list( filter(lambda a_b__c: a_b__c[0][0] in ['base'], ordered_build_files)) build = list( filter( lambda a_b__c: a_b__c[0][0] in ['build_service', 'build_docker'], ordered_build_files)) test = list( filter( lambda a_b__c: a_b__c[0][ 0] in ['build_tests', 'test', 'shell', 'run_link', 'run'], ordered_build_files)) deploy = list( filter(lambda a_b__c: a_b__c[0][0] in ['deploy'], ordered_build_files)) if len(base) + len(build) + len(test) + len(deploy) != len( ordered_build_files): raise Exception( 'Something went wrong when reorganizing build steps. One of the commands is probably missing.' ) ordered_build_files = [('Building Docker', base), ('Building App', build), ('Running and Testing App', test)] if not common.is_pr: ordered_build_files.append( ('Deploying', list(deploy)) ) # build_service needs to be before others otherwise it may mess-up with tests # Display commands common.logger.info("Okay, here is the plan:") for stage, commands in ordered_build_files: if len(commands) > 0: common.logger.info("## %s ##" % (stage)) for (command, service), order in commands: # Sanity check sub_task_orders = [ build_files_order[a] for a in service_dependencies[(command, service)] ] if any(map(lambda o: order <= o, sub_task_orders)): raise DMakeException('Bad ordering') common.logger.info("- %s @ %s" % (command, service)) # Generate the list of command to run all_commands = [] append_command(all_commands, 'env', var="REPO", value=common.repo) append_command(all_commands, 'env', var="COMMIT", value=common.commit_id) append_command(all_commands, 'env', var="BUILD", value=common.build_id) append_command(all_commands, 'env', var="BRANCH", value=common.branch) append_command(all_commands, 'env', var="ENV_TYPE", value=common.env_type) append_command(all_commands, 'env', var="DMAKE_TMP_DIR", value=common.tmp_dir) for stage, commands in ordered_build_files: if len(commands) > 0: append_command(all_commands, 'stage', name=stage, concurrency=1 if stage == "Deploying" else None) for (command, service), order in commands: append_command(all_commands, 'sh', shell='echo "Running %s @ %s"' % (command, service)) if command in ['build_tests', 'build_service']: deepomake = loaded_files[service] else: file, _ = service_providers[service] deepomake = loaded_files[file] app_name = deepomake.get_app_name() links = docker_links[app_name] app_services = services[app_name] #try: if True: # HACK if command == "base": deepomake.generate_base(all_commands) elif command == "shell": deepomake.generate_shell(all_commands, service, app_services, links) elif command == "test": deepomake.generate_test(all_commands, service, app_services, links) elif command == "run": deepomake.generate_run(all_commands, service, links) elif command == "run_link": deepomake.generate_run_link(all_commands, service, links) elif command == "build_tests": deepomake.generate_build_tests(all_commands) elif command == "build_service": deepomake.generate_build_services(all_commands) elif command == "build_docker": deepomake.generate_build(all_commands, service) elif command == "deploy": deepomake.generate_deploy(all_commands, service, links) else: raise Exception("Unkown command '%s'" % command) # except DMakeException as e: # print(('ERROR in file %s:\n' % file) + str(e)) # sys.exit(1) # Check stages do not appear twice (otherwise it may block Jenkins) stage_names = set() for cmd, kwargs in all_commands: if cmd == "stage": name = kwargs['name'] if name in stage_names: raise DMakeException('Duplicate stage name: %s' % name) else: stage_names.add(name) # If not on Pull Request, tag the commit as deployed if dmake_command == "deploy" and not common.is_pr: append_command(all_commands, 'git_tag', tag='deployed_version_%s' % common.branch) # Generate output if common.is_local: file_to_generate = os.path.join(common.tmp_dir, "DMakefile") else: file_to_generate = "DMakefile" generate_command(file_to_generate, all_commands) common.logger.info("Output has been written to %s" % file_to_generate) # If on local, run the commands if common.is_local: result = os.system('bash %s' % file_to_generate) if result != 0 or dmake_command != 'run': os.system('deepomake_clean %s' % common.tmp_dir)
def generate_command_pipeline(file, cmds): file.write('{ ->\n') if common.build_description is not None: file.write("currentBuild.description = '%s'\n" % common.build_description.replace("'", "\\'")) file.write('node {\n') file.write('try {\n') # Check crendentials file.write( "try {withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'dmake-http', usernameVariable: '_', passwordVariable: '__']]) {}}\n" ) file.write( """catch(error) {\nsh('echo "WARNING: Jenkins credentials \\'dmake-http\\' are not defined: you won\\'t be able to deploy only the part of your app that have changed."')\n}\n""" ) for cmd, kwargs in cmds: if cmd == "stage": name = kwargs['name'].replace("'", "\\'") if kwargs['concurrency'] is not None: file.write("stage concurrency: %s, name: '%s'\n" % (str(kwargs['concurrency']), name)) else: file.write("stage '%s'\n" % name) elif cmd == "sh": commands = kwargs['shell'] if common.is_string(commands): commands = [commands] commands = [ c.replace("'", "\\'").replace("$", "\\$") for c in commands ] if len(commands) == 0: return if len(commands) == 1: file.write("sh('%s')\n" % commands[0]) else: file.write('parallel (\n') commands_list = [] for c in enumerate(commands): commands_list.append("cmd%d: { sh('%s') }" % c) file.write(',\n'.join(commands_list)) file.write(')\n') elif cmd == "read_sh": file_output = os.path.join(common.root_dir, ".dmake", "output_%d" % kwargs['id']) file.write("sh('%s > %s')\n" % (kwargs['shell'], file_output)) file.write("env.%s = readFile '%s'\n" % (kwargs['var'], file_output)) if kwargs['fail_if_empty']: file.write("sh('if [ -z \"${%s}\" ]; then exit 1; fi')\n" % kwargs['var']) elif cmd == "env": file.write('env.%s = "%s"\n' % (kwargs['var'], kwargs['value'])) elif cmd == "git_tag": url = common.repo_url if url is not None and (url.startswith('https://') or url.startswith('http://')): i = url.find(':') prefix = url[:i] host = url[(i + 3):] file.write("sh('git tag --force %s')\n" % kwargs['tag']) file.write('try {\n') file.write( "withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'dmake-http', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD']]) {\n" ) file.write("sh('env')\n") file.write('try {\n') file.write( "sh('git push %s://${GIT_USERNAME}:${GIT_PASSWORD}@%s --force --tags')\n" % (prefix, host)) file.write("""} catch(error) {\nsh('echo "%s"')\n}\n""" % tag_push_error_msg.replace("'", "\\'")) file.write("}\n") file.write( """} catch(error) {\nsh('echo "Credentials \\'dmake-http\\' are not defined, skipping tag pushing."')\n}\n""" ) elif cmd == "junit": file.write("junit '%s'\n" % kwargs['report']) elif cmd == "cobertura": pass elif cmd == "publishHTML": file.write( "publishHTML(target: [allowMissing: false, alwaysLinkToLastBuild: true, keepAll: false, reportDir: '%s', reportFiles: '%s', reportName: '%s'])\n" % (kwargs['directory'], kwargs['index'], kwargs['title'].replace("'", "\'"))) elif cmd == "build": parameters = [] for var, value in kwargs['parameters'].items(): value = common.eval_str_in_env(value) parameters.append( "string(name: '%s', value: '%s')" % (var.replace("'", "\\'"), value.replace("'", "\\'"))) parameters = ','.join(parameters) file.write( "build job: '%s', parameters: [%s], propagate: %s, wait: %s\n" % (kwargs['job'].replace("'", "\\'"), parameters, "true" if kwargs['propagate'] else "false", "true" if kwargs['wait'] else "false")) else: raise DMakeException("Unknown command %s" % cmd) file.write('}\n') file.write('finally {\n') file.write('sh("deepomake_clean %s")\n' % common.tmp_dir) file.write('sh("sudo chown jenkins:jenkins * -R")\n') file.write('}\n}}\n')
def _validate_type_(self, path, data_type, data): if data_type == "bool": if not isinstance(data, bool): raise WrongType("Expecting bool") return data elif data_type == "int": if isinstance(data, int) or isinstance(data, float): data = int(data) if not isinstance(data, int): raise WrongType("Expecting int") return str(data) elif data_type == "string": if isinstance(data, int) or isinstance(data, float): data = str(data) if not common.is_string(data): raise WrongType("Expecting string") if not self.blank and data == "": raise WrongType("Expecting non-blank string") if self.no_slash_no_space: for c in ['/', ' ']: if data.find(c) >= 0: raise ValidationError("Character '%s' not allowed" % c) return data elif data_type == "path" or data_type == "dir": if not common.is_string(data): raise WrongType("Expecting string") if len(data) > 0 and data[0] == '/': data = data[1:] full_path = data if self.child_path_only: if full_path.startswith(path): data = data[len(path)] if len(data) > 0 and data[0] == '/': data = data[1:] else: raise WrongType( "Path must be sub-paths to deepomake file for this field." ) else: full_path = os.path.join(path, data) if not self.child_path_only: data = full_path data = os.path.normpath(data) if data.startswith("../"): raise WrongType( "Trying to access a parent directory is forbidden") if self.check_path: if data_type == "path": if not os.path.isfile(full_path): raise WrongType("Could not find file: %s" % data) if self.executable and not os.access(full_path, os.X_OK): raise WrongType("The file must be executable: %s" % full_path) else: if not os.path.isdir(full_path): raise WrongType("Could not find directory: %s" % data) return data elif data_type == "array": if not isinstance(data, list): raise WrongType("Expecting array") valid_data = [] for d in data: child = copy.deepcopy(self.child) valid_data.append(child._validate_(path, d)) return valid_data elif data_type == "dict": if not isinstance(data, dict): raise WrongType("Expecting dict") valid_data = {} for k, d in data.items(): child = copy.deepcopy(self.child) try: valid_data[k] = child._validate_(path, d) except ValidationError as e: raise ValidationError("Error with field '%s': %s" % (k, str(e))) return valid_data else: raise DMakeException("Unkown data type: %s" % data_type)
def _get_service_(self, service): for t in self.services: t_name = "%s/%s" % (self.app_name, t.service_name) if t_name == service: return t raise DMakeException("Could not find service '%s'" % service)