def get_commands_from_history(image_layer): '''Given the image layer object and the shell, get the list of command objects that created the layer''' # set up notice origin for the layer origin_layer = 'Layer: ' + image_layer.fs_hash[:10] if image_layer.created_by: instruction = created_to_instruction(image_layer.created_by) image_layer.origins.add_notice_to_origins( origin_layer, Notice( formats.dockerfile_line.format( dockerfile_instruction=instruction), 'info')) else: image_layer.origins.add_notice_to_origins( origin_layer, Notice(formats.no_created_by, 'warning')) command_line = instruction.split(' ', 1)[1] # Image layers are created with the directives RUN, ADD and COPY # For ADD and COPY instructions, there is no information about the # packages added if 'ADD' in instruction or 'COPY' in instruction: image_layer.origins.add_notice_to_origins( origin_layer, Notice(errors.unknown_content.format(files=command_line), 'warning')) # return an empty list as we cannot find any commands return [] else: # for RUN instructions we can return a list of commands command_list, msg = common.filter_install_commands(command_line) if msg: image_layer.origins.add_notice_to_origins(origin_layer, Notice(msg, 'warning')) return command_list
def get_dockerfile_packages(): '''Given a Dockerfile return an approximate image object. This is mosty guess work and shouldn't be relied on for accurate information. Add Notice messages indicating as such: 1. Create an image with a placeholder repotag 2. For each RUN command, create a package list 3. Create layer objects with incremental integers and add the package list to that layer with a Notice about parsing 4. Return stub image''' stub_image = Image('easteregg:cookie') layer_count = 0 for inst in docker.docker_commands: if inst[0] == 'RUN': layer_count = layer_count + 1 layer = ImageLayer(layer_count) install_commands, msg = common.filter_install_commands(inst[1]) if msg: layer.origins.add_notice_to_origins( inst[1], Notice(msg, 'info')) pkg_names = [] for command in install_commands: pkg_names.append(common.get_installed_package_names(command)) for pkg_name in pkg_names: pkg = Package(pkg_name) # shell parser does not parse version pins yet # when that is enabled, Notices for no versions need to be # added here layer.add_package(pkg) return stub_image
def add_packages_from_history(image_obj, shell): '''Given a DockerImage object, get package objects installed in each layer Assume that the imported images have already gone through this process and have their layer's packages populated. So collecting package object occurs from the last linked layer: 1. For each layer get a list of package names 2. For each package name get a list of dependencies 3. Create a list of package objects with metadata 4. Add this to the layer''' image_layers = image_obj.layers[image_obj.get_last_import_layer() + 1:] logger.debug('Retrieving metadata for remaining {} layers'.format( len(image_layers))) for layer in image_layers: instruction = created_to_instruction(layer.created_by) origin_layer = instruction + ' -> ' + layer.diff_id[:10] layer.origins.add_notice_origin(origin_layer) origin_info = formats.invoke_for_snippets layer.origins.add_notice_origin(origin_info) if 'RUN' in instruction: # for Docker the created_by comes from the instruction in the # dockerfile run_command_line = instruction.split(' ', 1)[1] cmd_list, msg = common.filter_install_commands(run_command_line) if msg: layer.origins.add_notice_to_origins(origin_info, Notice(msg, 'warning')) for command in cmd_list: origin_cmd = content.print_package_invoke(command.name) layer.origins.add_notice_origin(origin_cmd) pkg_list = common.get_installed_package_names(command) all_pkgs = [] for pkg_name in pkg_list: pkg_listing = command_lib.get_package_listing( command.name, pkg_name) deps, deps_msg = common.get_package_dependencies( pkg_listing, pkg_name, shell) if deps_msg: logger.warning(deps_msg) all_pkgs.append(pkg_name) all_pkgs.extend(deps) unique_pkgs = list(set(all_pkgs)) for pkg_name in unique_pkgs: pkg = Package(pkg_name) pkg_listing = command_lib.get_package_listing( command.name, pkg_name) common.fill_package_metadata(pkg, pkg_listing, shell) layer.add_package(pkg)