Example #1
0
    def retrieve_apiversions(libfullpath):
        """Retrieve version definitions from .so library
           using readelf binary

        Args:
            libfullpath (string): fullpath to .so library

        Returns:
            array[String]: version definitions
        """
        if not os.path.exists(libfullpath):
            return []

        apiversions = []
        command = f"readelf -V {libfullpath}"
        ## logger.debug(f"Executing command: {command}")
        success, output = Utils.run_process_and_return_output(command)
        if success == 0:
            ## parses something like below to get out 'GLIBC_2.6' :
            ## 0x005c: Rev: 1  Flags: none  Index: 4  Cnt: 2  Name: GLIBC_2.6
            in_version_definition_section = False
            for line in output.splitlines():
                if (in_version_definition_section):
                    if ("Version needs section" in line):
                        in_version_definition_section = False
                    TAG = "Name: "
                    idx = line.find(TAG)
                    if (line.startswith("  0x") and (idx > 0)):
                        apiversions.append(line[idx+len(TAG):])
                elif ("Version definition section" in line):
                    in_version_definition_section = True
        return apiversions
Example #2
0
    def unpack_image(self, tag, delete=False):
        """Attempt to unpack an OCI image in a given directory to an OCI bundle
        without any modifications

        Calls out to umoci to handle the base conversion
        """
        # If umoci isn't installed, can't unpack
        if not self.umoci_found:
            logger.error("Cannot unpack image as cannot find umoci")
            return

        umoci_command = f'umoci unpack --rootless --image {self.src}:{tag} {self.dest}'

        logger.debug(umoci_command)

        success = Utils().run_process(umoci_command)
        if success == 0:
            logger.info(f"Unpacked image successfully to {self.dest}")

            if delete:
                logger.debug("Deleting downloaded image")
                shutil.rmtree(self.src)

            return True
        else:
            logger.warning("Umoci failed to unpack the image")
            return False
Example #3
0
    def download_image(self, url, creds, platform_cfg):
        """Attempt to download the specified image using skopeo

        Will download and extract the image to /tmp

        Args:
            url (string): URL to download the image from (e.g. docker://hello-world:latest)
            creds (string): Credentials for the OCI registry in the form username:password
            platform_cfg (dict): Platform template

        Returns:
            string: Path to downloaded image
        """
        # If skopeo isn't installed, can't download
        if not self.skopeo_found:
            logger.error("Cannot download image as cannot find skopeo")
            return

        image_tag = self.get_image_tag(url)

        # Get arch from config
        if 'arch' not in platform_cfg:
            logger.error("Platform architecture is not defined", err=True)
            return ""
        else:
            arch = platform_cfg['arch'].get('arch')
            variant = platform_cfg['arch'].get('variant')

        if 'os' not in platform_cfg:
            logger.error("Platform OS is not defined", err=True)
            return ""
        else:
            platform_os = platform_cfg.get('os')

        # Save the image to a temp dir. Use uuid to generate a unique name
        if not os.path.exists('/tmp/bundlegen'):
            os.makedirs('/tmp/bundlegen')

        now = time.strftime("%Y%m%d-%H%M%S")
        destination = f'/tmp/bundlegen/{now}_{Utils.get_random_string()}'
        logger.info(f"Downloading image to {destination}...")

        # Build the command to skopeo
        skopeo_command = f'skopeo '

        if (os.path.exists(
                os.path.expanduser('~/.config/containers/policy.json'))
                or os.path.exists('/etc/containers/policy.json')):
            logger.debug('Found a policy.json file for skopeo')
        else:
            logger.debug(
                'Did not find a policy.json file for skopeo. Will use insecure-policy flag for skopeo!'
            )
            skopeo_command += '--insecure-policy '

        if creds:
            skopeo_command += f'--src-creds {creds} '

        if variant:
            skopeo_command += f'--override-os {platform_os} --override-arch {arch} --override-variant {variant} '
        else:
            skopeo_command += f'--override-os {platform_os} --override-arch {arch} '

        skopeo_command += f'copy {url} oci:{destination}:{image_tag}'

        logger.debug(skopeo_command)

        # Run skopeo, and stream the output to the console
        success = Utils.run_process(skopeo_command)
        if success == 0:
            logger.success(
                f"Downloaded image from {url} successfully to {destination}")
            return destination
        else:
            logger.warning("Skopeo failed to download the image")
            return None
Example #4
0
def generate_bundle(options: message.Message) -> Tuple[Result, str]:
    """
    Actually do the work to generate the bundle
    """

    # Create a random dir to save the generated bundle, before copying to output directory
    outputdir = os.path.abspath(
        os.path.join(os.environ.get('BUNDLEGEN_TMP_DIR'),
                     Utils.get_random_string(5)))

    selected_platform = STBPlatform(
        options.platform, options.searchpath
        or os.environ.get('RDK_PLATFORM_SEARCHPATH'))

    if not selected_platform.found_config():
        logger.error(f"Could not find config for platform {options.platform}")
        return (Result.FATAL_ERROR, "")

    if not options.image_url:
        logger.error("Image URL is not set - cannot generate bundle")
        return (Result.FATAL_ERROR, "")

    logger.success(
        f"Starting Bundle Generation from image '{options.image_url}' for platform {options.platform} (UUID: {options.uuid})"
    )

    creds = os.environ.get("RDK_OCI_REGISTRY_CREDS")
    img_downloader = ImageDownloader()
    img_path = img_downloader.download_image(options.image_url, creds,
                                             selected_platform.get_config())

    if not img_path:
        logger.error("Failed to download image")
        return (Result.TRANSIENT_ERROR, "")

    # Unpack the image with umoci
    tag = ImageDownloader().get_image_tag(options.image_url)
    img_unpacker = ImageUnpackager(img_path, outputdir)
    img_unpacker.unpack_image(tag, delete=True)

    # Load app metadata
    metadata_from_image = img_unpacker.get_app_metadata_from_img()
    custom_app_metadata = options.app_metadata

    app_metadata_dict = {}
    if not metadata_from_image and not custom_app_metadata:
        # No metadata at all
        logger.error(
            f"Cannot find app metadata file in OCI image and none provided to BundleGen"
        )
        return (Result.FATAL_ERROR, "")

    if not metadata_from_image and custom_app_metadata:
        # Use custom metadata
        app_metadata_dict = custom_app_metadata
    elif metadata_from_image and custom_app_metadata:
        logger.warning(
            "Image contains app metadata and custom metadata provided. Using custom metadata"
        )
        app_metadata_dict = custom_app_metadata
        img_unpacker.delete_img_app_metadata()
    else:
        app_metadata_dict = metadata_from_image
        img_unpacker.delete_img_app_metadata()

    if options.app_id:
        app_metadata_dict['id'] = options.app_id

    # Begin processing. Work in the output dir where the img was unpacked to
    processor = BundleProcessor(
        selected_platform.get_config(),
        outputdir,
        app_metadata_dict,
        False,
        options.lib_match_mode.value,
        options.createmountpoints,
    )

    if not processor.check_compatibility():
        # Not compatible - delete any work done so far
        shutil.rmtree(outputdir)
        logger.error(
            f"App is not compatible with platform {options.platform}, cannot generate bundle"
        )
        return (Result.FATAL_ERROR, "")

    success = processor.begin_processing()
    if not success:
        logger.error("Failed to generate bundle")
        # This might have been some weird issue, so re-queue to try again later
        return (Result.TRANSIENT_ERROR, "")

    if options.output_filename:
        tarball_name = options.output_filename
    else:
        tarball_name = app_metadata_dict["id"] + Utils.get_random_string(6)

    tmp_path = os.path.join(os.environ.get('BUNDLEGEN_TMP_DIR'),
                            f"{tarball_name}.tar.gz")
    persistent_path = os.path.join(
        options.outputdir or os.environ.get('BUNDLE_STORE_DIR'),
        f"{tarball_name}.tar.gz")

    tarball_settings = processor.platform_cfg.get('tarball')
    file_ownership_user = tarball_settings.get(
        'fileOwnershipSameAsUser') if tarball_settings else None
    file_mask = tarball_settings.get('fileMask') if tarball_settings else None

    container_uid_gid = processor.get_real_uid_gid()
    uid = container_uid_gid[
        0] if container_uid_gid[0] and file_ownership_user else None
    gid = container_uid_gid[
        1] if container_uid_gid[1] and file_ownership_user else None

    Utils.create_tgz(outputdir, tmp_path, uid, gid, file_mask)

    # Move to persistent storage
    logger.debug(
        f"Moving '{tmp_path}' to {options.outputdir or os.environ.get('BUNDLE_STORE_DIR')}"
    )
    shutil.move(tmp_path, options.outputdir
                or os.environ.get('BUNDLE_STORE_DIR'))

    return (Result.SUCCESS, persistent_path)
Example #5
0
def index():
    get_templates()
    form = GenerateForm()
    form.platform.choices = get_templates()

    if request.method == 'GET':
        return render_template('index.html', form=form)

    if form.validate_on_submit():
        print("Valid form submission")

        # Do BundleGen work
        outputdir = os.path.abspath(
            os.path.join(TMP_DIR, Utils.get_random_string(5)))
        selected_platform = STBPlatform(form.platform.data)

        if not selected_platform.found_config():
            print(f"Could not find config for platform {form.platform.data}")
            raise AppError("Could not find platform")

        img_url = ""
        creds = ""
        if form.image_url.data:
            # If downloading from URL, just use that as-is
            img_url = form.image_url.data
            # Add creds if given
            if form.registry_uname.data and form.registry_password.data:
                creds = f"{form.registry_uname.data}:{form.registry_password.data}"

        elif form.uploaded_img.data:
            # Got an uploaded image (hopefully a tar.gz!)
            f = form.uploaded_img.data
            filename = secure_filename(f.filename)
            upload_filepath = os.path.join(UPLOAD_FOLDER, filename)
            f.save(upload_filepath)

            # Extract tar
            # Extract the .tar to a temp directory
            img_temp_path = tempfile.mkdtemp()
            with tarfile.open(upload_filepath) as tar:
                tar.extractall(img_temp_path)

            # Delete tar
            os.remove(upload_filepath)

            img_url = f"oci:{img_temp_path}:latest"
            creds = None

        if not img_url:
            print("IMG URL is empty")
            raise AppError("Image URL cannot be empty")

        # Download Image
        img_downloader = ImageDownloader()
        img_path = img_downloader.download_image(
            img_url, creds, selected_platform.get_config())

        if not img_path:
            logger.error("Failed to download image")
            raise AppError("Image download failed")

        # Unpack the image with umoci
        tag = ImageDownloader().get_image_tag(img_url)
        img_unpacker = ImageUnpackager(img_path, outputdir)
        img_unpacker.unpack_image(tag, delete=True)

        # Load app metadata
        metadata_from_image = img_unpacker.get_app_metadata_from_img()
        custom_app_metadata = form.app_metadata.data

        app_metadata_dict = {}
        if not metadata_from_image and not custom_app_metadata:
            # No metadata at all
            logger.error(
                f"Cannot find app metadata file in OCI image and none provided to BundleGen"
            )
            raise AppError("No Metadata provided")

        if not metadata_from_image and custom_app_metadata:
            # Use custom metadata
            app_metadata_dict = json.loads(custom_app_metadata)
        elif metadata_from_image and custom_app_metadata:
            logger.warning(
                "Image contains app metadata and custom metadata provided. Using custom metadata"
            )
            app_metadata_dict = json.loads(custom_app_metadata)
            img_unpacker.delete_img_app_metadata()
        else:
            app_metadata_dict = metadata_from_image
            img_unpacker.delete_img_app_metadata()

        # Begin processing. Work in the output dir where the img was unpacked to
        processor = BundleProcessor(selected_platform.get_config(), outputdir,
                                    app_metadata_dict, False,
                                    form.lib_match.data)
        if not processor.check_compatibility():
            # Not compatible - delete any work done so far
            shutil.rmtree(outputdir)
            raise AppError("App incompatible")

        success = processor.begin_processing()

        if not success:
            logger.warning("Failed to produce bundle")
            raise AppError("Something went wrong")

        tarball_name = app_metadata_dict["id"] + Utils.get_random_string(6)

        Utils.create_tgz(outputdir, tarball_name)
        logger.success(
            f"Successfully generated bundle at {tarball_name}.tar.gz")

        # Move to persistant storage
        print(f"Moving '{tarball_name}.tar.gz' to {BUNDLE_STORE_DIR}")
        shutil.move(f'{tarball_name}.tar.gz', BUNDLE_STORE_DIR)

        return jsonify(success=True)
Example #6
0
def generate(image, outputdir, platform, appmetadata, searchpath, creds, yes):
    """Generate an OCI Bundle for a specified platform
    """

    logger.info(f'Generating new OCI bundle* from {image} for {platform}')

    outputdir = os.path.abspath(outputdir)

    # Check if the output dir already exists
    if os.path.exists(outputdir):
        if not yes:
            click.confirm(
                f"The directory {outputdir} already exists. Are you sure you want to continue? The contents of this directory will be deleted",
                abort=True)

        # Delete existing directory
        shutil.rmtree(outputdir)

    # Load the config for the platform
    selected_platform = STBPlatform(platform, searchpath)

    if not selected_platform.found_config():
        logger.error(f"Could not find config for platform {platform}")
        return

    # Get the app metadata as a dictionary
    # TODO:: Metadata will be embedded in the image moving forward
    app_metadata_dict = {}
    if os.path.exists(appmetadata):
        with open(appmetadata) as metadata:
            app_metadata_dict = json.load(metadata)
    else:
        logger.error(f"Cannot find app metadata file {appmetadata}")
        return

    # Download the image to a temp directory
    img_downloader = ImageDownloader()
    img_path = img_downloader.download_image(image, creds,
                                             selected_platform.get_config())

    if not img_path:
        return

    # Unpack the image with umoci
    tag = ImageDownloader().get_image_tag(image)
    img_unpacker = ImageUnpackager()
    unpack_success = img_unpacker.unpack_image(img_path, tag, outputdir)

    if not unpack_success:
        return

    # Delete the downloaded image now we've unpacked it
    logger.info(f"Deleting {img_path}")
    shutil.rmtree(img_path)

    # Begin processing. Work in the output dir where the img was unpacked to
    processor = BundleProcessor(selected_platform.get_config(), outputdir,
                                app_metadata_dict)
    if not processor.check_compatibility():
        # Not compatible - delete any work done so far
        shutil.rmtree(outputdir)
        return

    success = processor.begin_processing()

    if not success:
        logger.warning("Failed to produce bundle")
        return

    # Processing finished, now create a tarball of the output directory
    Utils.create_tgz(outputdir, outputdir)

    logger.success(f"Successfully generated bundle at {outputdir}.tar.gz")
Example #7
0
def generate(image, outputdir, platform, searchpath, creds, ipk, appmetadata,
             yes, nodepwalking, libmatchingmode):
    """Generate an OCI Bundle for a specified platform
    """

    logger.info(f'Generating new OCI bundle* from {image} for {platform}')

    outputdir = os.path.abspath(outputdir)

    # Check if the output dir already exists
    if os.path.exists(outputdir):
        if not yes:
            click.confirm(
                f"The directory {outputdir} already exists. Are you sure you want to continue? The contents of this directory will be deleted",
                abort=True)

        # Delete existing directory
        shutil.rmtree(outputdir)

    # Load the config for the platform
    selected_platform = STBPlatform(platform, searchpath)

    if not selected_platform.found_config():
        logger.error(f"Could not find config for platform {platform}")
        return

    # Download the image to a temp directory
    img_downloader = ImageDownloader()
    img_path = img_downloader.download_image(image, creds,
                                             selected_platform.get_config())

    if not img_path:
        return

    # Unpack the image with umoci
    tag = ImageDownloader().get_image_tag(image)
    img_unpacker = ImageUnpackager()
    unpack_success = img_unpacker.unpack_image(img_path, tag, outputdir)

    if not unpack_success:
        return

    # Delete the downloaded image now we've unpacked it
    logger.info(f"Deleting {img_path}")
    shutil.rmtree(img_path)

    # Load app metadata
    app_metadata_file = ""
    app_metadata_image_path = os.path.join(outputdir, "rootfs",
                                           "appmetadata.json")

    image_metadata_exists = os.path.exists(app_metadata_image_path)

    if not image_metadata_exists and not appmetadata:
        # No metadata at all
        logger.error(
            f"Cannot find app metadata file in OCI image and none provided to BundleGen"
        )
        return
    elif not image_metadata_exists and appmetadata:
        # No metadata in image, but custom file provided
        if not os.path.exists(appmetadata):
            logger.error(f'App metadata file {appmetadata} does not exist')
            return
        app_metadata_file = appmetadata
    elif image_metadata_exists and appmetadata:
        # Got two options for metadata, which one do we want?
        if click.confirm(
                "Metadata found in image, but custom metadata provided. Use custom metadata?"
        ):
            app_metadata_file = appmetadata
        else:
            app_metadata_file = app_metadata_image_path
    else:
        app_metadata_file = app_metadata_image_path

    logger.debug(f"Loading metadata from {app_metadata_file}")

    # Load the metadata
    app_metadata_dict = {}
    with open(app_metadata_file) as metadata:
        app_metadata_dict = json.load(metadata)

    # remove app metadata from image rootfs
    if image_metadata_exists:
        os.remove(app_metadata_image_path)

    # Begin processing. Work in the output dir where the img was unpacked to
    processor = BundleProcessor(selected_platform.get_config(), outputdir,
                                app_metadata_dict, nodepwalking,
                                libmatchingmode)
    if not processor.check_compatibility():
        # Not compatible - delete any work done so far
        shutil.rmtree(outputdir)
        return

    success = processor.begin_processing()

    if not success:
        logger.warning("Failed to produce bundle")
        return

    # Processing finished, now create a tarball/ipk of the output directory
    if ipk:
        # create control file
        Utils.create_control_file(selected_platform.get_config(),
                                  app_metadata_dict)
        Utils.create_ipk(outputdir, outputdir)
        logger.success(f"Successfully generated bundle at {outputdir}.ipk")
    else:
        Utils.create_tgz(outputdir, outputdir)
        logger.success(f"Successfully generated bundle at {outputdir}.tar.gz")
Example #8
0
def generate(image, outputdir, platform, searchpath, creds, ipk, appmetadata, yes, nodepwalking, libmatchingmode, createmountpoints, appid):
    """Generate an OCI Bundle for a specified platform
    """

    logger.info(f'Generating new OCI bundle* from {image} for {platform}')

    outputdir = os.path.abspath(outputdir)

    # Check if the output dir already exists
    if os.path.exists(outputdir):
        if not yes:
            click.confirm(
                f"The directory {outputdir} already exists. Are you sure you want to continue? The contents of this directory will be deleted", abort=True)

        # Delete existing directory
        shutil.rmtree(outputdir)

    # Load the config for the platform
    selected_platform = STBPlatform(platform, searchpath)

    if not selected_platform.found_config():
        logger.error(f"Could not find config for platform {platform}")
        sys.exit(1)

    # Download the image to a temp directory
    img_downloader = ImageDownloader()
    img_path = img_downloader.download_image(
        image, creds, selected_platform.get_config())

    if not img_path:
        sys.exit(1)

    # Unpack the image with umoci
    tag = ImageDownloader().get_image_tag(image)
    img_unpacker = ImageUnpackager(src=img_path, dst=outputdir)
    unpack_success = img_unpacker.unpack_image(tag, delete=True)

    if not unpack_success:
        sys.exit(1)

    # Load app metadata
    metadata_from_image = img_unpacker.get_app_metadata_from_img()
    appmetadata = os.path.abspath(appmetadata) if appmetadata else None

    app_metadata_dict = {}
    if not metadata_from_image and not appmetadata:
        # No metadata at all
        logger.error(
            f"Cannot find app metadata file in OCI image and none provided to BundleGen")
        sys.exit(1)

    if not metadata_from_image and appmetadata:
        # No metadata in image, but custom file provided
        if not os.path.exists(appmetadata):
            logger.error(f'App metadata file {appmetadata} does not exist')
            sys.exit(1)
        with open(appmetadata) as metadata:
            logger.debug(f"Loading metadata from {appmetadata}")
            app_metadata_dict = json.load(metadata)
    elif metadata_from_image and appmetadata:
        # Got two options for metadata, which one do we want?
        if click.confirm("Metadata found in image, but custom metadata provided. Use custom metadata?"):
            with open(appmetadata) as metadata:
                logger.debug(f"Loading metadata from {appmetadata}")
                app_metadata_dict = json.load(metadata)
        else:
            app_metadata_dict = metadata_from_image

        img_unpacker.delete_img_app_metadata()
    else:
        # Take metadata from image
        app_metadata_dict = metadata_from_image
        img_unpacker.delete_img_app_metadata()

    if appid:
         app_metadata_dict['id'] = appid

    # Begin processing. Work in the output dir where the img was unpacked to
    processor = BundleProcessor(
        selected_platform.get_config(), outputdir, app_metadata_dict, nodepwalking, libmatchingmode, createmountpoints)
    if not processor.check_compatibility():
        # Not compatible - delete any work done so far
        shutil.rmtree(outputdir)
        sys.exit(2)

    success = processor.begin_processing()

    if not success:
        logger.warning("Failed to produce bundle")
        sys.exit(3)

    # Processing finished, now create a tarball/ipk of the output directory
    if ipk:
        # create control file
        Utils.create_control_file(
            selected_platform.get_config(), app_metadata_dict)
        Utils.create_ipk(outputdir, outputdir)
        logger.success(f"Successfully generated bundle at {outputdir}.ipk")
    else:
        tarball_settings = processor.platform_cfg.get('tarball')
        file_ownership_user = tarball_settings.get('fileOwnershipSameAsUser') if tarball_settings else None
        file_mask = tarball_settings.get('fileMask') if tarball_settings else None

        container_uid_gid = processor.get_real_uid_gid()

        uid = container_uid_gid[0] if container_uid_gid[0] and file_ownership_user else None
        gid = container_uid_gid[1] if container_uid_gid[1] and file_ownership_user else None

        Utils.create_tgz(outputdir, outputdir, uid, gid, file_mask)
        logger.success(f"Successfully generated bundle at {outputdir}.tar.gz")