def build_image(args): subvol = Subvol(os.path.join(args.subvolumes_dir, args.subvolume_rel_path)) dep_graph = DependencyGraph(itertools.chain( gen_parent_layer_items( args.child_layer_target, args.parent_layer_json, args.subvolumes_dir, ), gen_items_for_features( feature_paths=[args.child_feature_json], target_to_path=make_target_path_map(args.child_dependencies), yum_from_repo_snapshot=args.yum_from_repo_snapshot, ), )) for phase in dep_graph.ordered_phases(): phase.build(subvol) # We cannot validate or sort `ImageItem`s until the phases are # materialized since the items may depend on the output of the phases. for item in dep_graph.gen_dependency_order_items(subvol.path().decode()): item.build(subvol) # Build artifacts should never change. subvol.set_readonly(True) try: return SubvolumeOnDisk.from_subvolume_path( subvol.path().decode(), args.subvolumes_dir, ) except Exception as ex: raise RuntimeError(f'Serializing subvolume {subvol.path()}') from ex
def build_image(args): subvol = Subvol(os.path.join(args.subvolumes_dir, args.subvolume_rel_path)) target_to_path = make_target_path_map(args.child_dependencies) # This stack allows build items to hold temporary state on disk. with ExitStack() as exit_stack: dep_graph = DependencyGraph( itertools.chain( gen_parent_layer_items( args.child_layer_target, args.parent_layer_json, args.subvolumes_dir, ), gen_items_for_features( exit_stack=exit_stack, feature_paths=[args.child_feature_json], target_to_path=target_to_path, ), )) layer_opts = LayerOpts( layer_target=args.child_layer_target, yum_from_snapshot=args.yum_from_repo_snapshot, build_appliance=None if not args.build_appliance_json else get_subvolume_path(args.build_appliance_json, args.subvolumes_dir), ) # Creating all the builders up-front lets phases validate their input for builder in [ builder_maker(items, layer_opts) for builder_maker, items in dep_graph.ordered_phases() ]: builder(subvol) # We cannot validate or sort `ImageItem`s until the phases are # materialized since the items may depend on the output of the phases. for item in dep_graph.gen_dependency_order_items( subvol.path().decode()): build_item( item, subvol=subvol, target_to_path=target_to_path, subvolumes_dir=args.subvolumes_dir, ) # Build artifacts should never change. Run this BEFORE the exit_stack # cleanup to enforce that the cleanup does not touch the image. subvol.set_readonly(True) try: return SubvolumeOnDisk.from_subvolume_path( # Converting to a path here does not seem too risky since this # class shouldn't have a reason to follow symlinks in the subvol. subvol.path().decode(), args.subvolumes_dir, ) # The complexity of covering this is high, but the only thing that can # go wrong is a typo in the f-string. except Exception as ex: # pragma: no cover raise RuntimeError(f'Serializing subvolume {subvol.path()}') from ex
def build_image(args): # We want check the umask since it can affect the result of the # `os.access` check for `image.install*` items. That said, having a # umask that denies execute permission to "user" is likely to break this # code earlier, since new directories wouldn't be traversible. At least # this check gives a nice error message. cur_umask = os.umask(0) os.umask(cur_umask) assert cur_umask & stat.S_IXUSR == 0, \ f'Refusing to run with pathological umask 0o{cur_umask:o}' subvol = Subvol(os.path.join(args.subvolumes_dir, args.subvolume_rel_path)) layer_opts = LayerOpts( layer_target=args.child_layer_target, yum_from_snapshot=args.yum_from_repo_snapshot, build_appliance=get_subvolume_path( args.build_appliance_json, args.subvolumes_dir, ) if args.build_appliance_json else None, preserve_yum_cache=args.preserve_yum_cache, artifacts_may_require_repo=args.artifacts_may_require_repo, target_to_path=make_target_path_map(args.child_dependencies), subvolumes_dir=args.subvolumes_dir, ) # This stack allows build items to hold temporary state on disk. with ExitStack() as exit_stack: dep_graph = DependencyGraph(gen_items_for_features( exit_stack=exit_stack, features_or_paths=args.child_feature_json, layer_opts=layer_opts, ), layer_target=args.child_layer_target) # Creating all the builders up-front lets phases validate their input for builder in [ builder_maker(items, layer_opts) for builder_maker, items in dep_graph.ordered_phases() ]: builder(subvol) # We cannot validate or sort `ImageItem`s until the phases are # materialized since the items may depend on the output of the phases. for item in dep_graph.gen_dependency_order_items( PhasesProvideItem( from_target=args.child_layer_target, subvol=subvol, )): item.build(subvol, layer_opts) # Build artifacts should never change. Run this BEFORE the exit_stack # cleanup to enforce that the cleanup does not touch the image. subvol.set_readonly(True) try: return SubvolumeOnDisk.from_subvolume_path( # Converting to a path here does not seem too risky since this # class shouldn't have a reason to follow symlinks in the subvol. subvol.path().decode(), args.subvolumes_dir, ) # The complexity of covering this is high, but the only thing that can # go wrong is a typo in the f-string. except Exception as ex: # pragma: no cover raise RuntimeError(f'Serializing subvolume {subvol.path()}') from ex