aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/openprotium-init
AgeCommit message (Expand)Author
2010-06-10recipes: bump PR/INC_PR for packages changed in RDEPENDS/RRECOMMENDS/RSUGGEST...Martin Jansa
2010-06-03recipes: conform to OE packaging guidelines with RDEPENDS/RRECOMMENDSMartin Jansa
2009-03-17rename packages/ to recipes/ per earlier agreementDenys Dmytriyenko
href='#n148'>148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
#!/usr/bin/env python3
#
# Copyright (c) 2014 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
#

# DESCRIPTION
# This script is used to test public autobuilder images on remote hardware.
# The script is called from a machine that is able download the images from the remote images repository and to connect to the test hardware.
#
# test-remote-image --image-type core-image-sato --repo-link http://192.168.10.2/images --required-packages rpm psplash
#
# Translation: Build the 'rpm' and 'pslash' packages and test a remote core-image-sato image using the http://192.168.10.2/images repository.
#
# You can also use the '-h' option to see some help information.

import os
import sys
import argparse
import logging
import shutil
from abc import ABCMeta, abstractmethod

# Add path to scripts/lib in sys.path;
scripts_path = os.path.abspath(os.path.dirname(os.path.abspath(sys.argv[0])))
lib_path = scripts_path + '/lib'
sys.path = sys.path + [lib_path]

import scriptpath
import argparse_oe

# Add meta/lib to sys.path
scriptpath.add_oe_lib_path()

import oeqa.utils.ftools as ftools
from oeqa.utils.commands import runCmd, bitbake, get_bb_var

# Add all lib paths relative to BBPATH to sys.path; this is used to find and import the target controllers.
for path in get_bb_var('BBPATH').split(":"):
    sys.path.insert(0, os.path.abspath(os.path.join(path, 'lib')))

# In order to import modules that contain target controllers, we need the bitbake libraries in sys.path .
bitbakepath = scriptpath.add_bitbake_lib_path()
if not bitbakepath:
    sys.stderr.write("Unable to find bitbake by searching parent directory of this script or PATH\n")
    sys.exit(1)

# create a logger
def logger_create():
    log = logging.getLogger('hwauto')
    log.setLevel(logging.DEBUG)

    fh = logging.FileHandler(filename='hwauto.log', mode='w')
    fh.setLevel(logging.DEBUG)

    ch = logging.StreamHandler(sys.stdout)
    ch.setLevel(logging.INFO)

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)

    log.addHandler(fh)
    log.addHandler(ch)

    return log

# instantiate the logger
log = logger_create()


# Define and return the arguments parser for the script
def get_args_parser():
    description = "This script is used to run automated runtime tests using remotely published image files. You should prepare the build environment just like building local images and running the tests."
    parser = argparse_oe.ArgumentParser(description=description)
    parser.add_argument('--image-types', required=True, action="store", nargs='*', dest="image_types", default=None, help='The image types to test(ex: core-image-minimal).')
    parser.add_argument('--repo-link', required=True, action="store", type=str, dest="repo_link", default=None, help='The link to the remote images repository.')
    parser.add_argument('--required-packages', required=False, action="store", nargs='*', dest="required_packages", default=None, help='Required packages for the tests. They will be built before the testing begins.')
    parser.add_argument('--targetprofile', required=False, action="store", nargs=1, dest="targetprofile", default='AutoTargetProfile', help='The target profile to be used.')
    parser.add_argument('--repoprofile', required=False, action="store", nargs=1, dest="repoprofile", default='PublicAB', help='The repo profile to be used.')
    parser.add_argument('--skip-download', required=False, action="store_true", dest="skip_download", default=False, help='Skip downloading the images completely. This needs the correct files to be present in the directory specified by the target profile.')
    return parser

class BaseTargetProfile(object, metaclass=ABCMeta):
    """
    This class defines the meta profile for a specific target (MACHINE type + image type).
    """

    def __init__(self, image_type):
        self.image_type = image_type

        self.kernel_file = None
        self.rootfs_file = None
        self.manifest_file = None
        self.extra_download_files = []          # Extra files (full name) to be downloaded. They should be situated in repo_link

    # This method is used as the standard interface with the target profile classes.
    # It returns a dictionary containing a list of files and their meaning/description.
    def get_files_dict(self):
        files_dict = {}

        if self.kernel_file:
            files_dict['kernel_file'] = self.kernel_file
        else:
            log.error('The target profile did not set a kernel file.')
            sys.exit(1)

        if self.rootfs_file:
            files_dict['rootfs_file'] = self.rootfs_file
        else:
            log.error('The target profile did not set a rootfs file.')
            sys.exit(1)

        if self.manifest_file:
            files_dict['manifest_file'] = self.manifest_file
        else:
            log.error('The target profile did not set a manifest file.')
            sys.exit(1)

        for idx, f in enumerate(self.extra_download_files):
            files_dict['extra_download_file' + str(idx)] = f

        return files_dict

class AutoTargetProfile(BaseTargetProfile):

    def __init__(self, image_type):
        super(AutoTargetProfile, self).__init__(image_type)
        self.image_name = get_bb_var('IMAGE_LINK_NAME', target=image_type)
        self.kernel_type = get_bb_var('KERNEL_IMAGETYPE', target=image_type)
        self.controller = self.get_controller()

        self.set_kernel_file()
        self.set_rootfs_file()
        self.set_manifest_file()
        self.set_extra_download_files()

    # Get the controller object that will be used by bitbake.
    def get_controller(self):
        from oeqa.controllers.testtargetloader import TestTargetLoader

        target_controller = get_bb_var('TEST_TARGET')
        bbpath = get_bb_var('BBPATH').split(':')

        if target_controller == "qemu":
            from oeqa.targetcontrol import QemuTarget
            controller = QemuTarget
        else:
            testtargetloader = TestTargetLoader()
            controller = testtargetloader.get_controller_module(target_controller, bbpath)
        return controller

    def set_kernel_file(self):
        postconfig = "QA_GET_MACHINE = \"${MACHINE}\""
        machine = get_bb_var('QA_GET_MACHINE', postconfig=postconfig)
        self.kernel_file = self.kernel_type + '-' + machine + '.bin'

    def set_rootfs_file(self):
        image_fstypes = get_bb_var('IMAGE_FSTYPES').split(' ')
        # Get a matching value between target's IMAGE_FSTYPES and the image fstypes suppoerted by the target controller.
        fstype = self.controller.match_image_fstype(d=None, image_fstypes=image_fstypes)
        if fstype:
            self.rootfs_file = self.image_name + '.' + fstype
        else:
            log.error("Could not get a compatible image fstype. Check that IMAGE_FSTYPES and the target controller's supported_image_fstypes fileds have common values.")
            sys.exit(1)

    def set_manifest_file(self):
        self.manifest_file = self.image_name + ".manifest"

    def set_extra_download_files(self):
        self.extra_download_files = self.get_controller_extra_files()
        if not self.extra_download_files:
            self.extra_download_files = []

    def get_controller_extra_files(self):
        controller = self.get_controller()
        return controller.get_extra_files()


class BaseRepoProfile(object, metaclass=ABCMeta):
    """
    This class defines the meta profile for an images repository.
    """

    def __init__(self, repolink, localdir):
        self.localdir = localdir
        self.repolink = repolink

    # The following abstract methods are the interfaces to the repository profile classes derived from this abstract class.

    # This method should check the file named 'file_name' if it is different than the upstream one.
    # Should return False if the image is the same as the upstream and True if it differs.
    @abstractmethod
    def check_old_file(self, file_name):
        pass

    # This method should fetch file_name and create a symlink to localname if set.
    @abstractmethod
    def fetch(self, file_name, localname=None):
        pass

class PublicAB(BaseRepoProfile):

    def __init__(self, repolink, localdir=None):
        super(PublicAB, self).__init__(repolink, localdir)
        if localdir is None:
            self.localdir = os.path.join(os.environ['BUILDDIR'], 'PublicABMirror')

    # Not yet implemented. Always returning True.
    def check_old_file(self, file_name):
        return True

    def get_repo_path(self):
        path = '/machines/'

        postconfig = "QA_GET_MACHINE = \"${MACHINE}\""
        machine = get_bb_var('QA_GET_MACHINE', postconfig=postconfig)
        if 'qemu' in machine:
            path += 'qemu/'

        postconfig = "QA_GET_DISTRO = \"${DISTRO}\""
        distro = get_bb_var('QA_GET_DISTRO', postconfig=postconfig)
        path += distro.replace('poky', machine) + '/'
        return path


    def fetch(self, file_name, localname=None):
        repo_path = self.get_repo_path()
        link = self.repolink + repo_path + file_name

        self.wget(link, self.localdir, localname)

    def wget(self, link, localdir, localname=None, extraargs=None):
        wget_cmd = '/usr/bin/env wget -t 2 -T 30 -nv --passive-ftp --no-check-certificate '

        if localname:
            wget_cmd += ' -O ' + localname + ' '

        if extraargs:
            wget_cmd += ' ' + extraargs + ' '

        wget_cmd += " -P %s '%s'" % (localdir, link)
        runCmd(wget_cmd)

class HwAuto():

    def __init__(self, image_types, repolink, required_packages, targetprofile, repoprofile, skip_download):
        log.info('Initializing..')
        self.image_types = image_types
        self.repolink = repolink
        self.required_packages = required_packages
        self.targetprofile = targetprofile
        self.repoprofile = repoprofile
        self.skip_download = skip_download
        self.repo = self.get_repo_profile(self.repolink)

    # Get the repository profile; for now we only look inside this module.
    def get_repo_profile(self, *args, **kwargs):
        repo = getattr(sys.modules[__name__], self.repoprofile)(*args, **kwargs)
        log.info("Using repo profile: %s" % repo.__class__.__name__)
        return repo

    # Get the target profile; for now we only look inside this module.
    def get_target_profile(self, *args, **kwargs):
        target = getattr(sys.modules[__name__], self.targetprofile)(*args, **kwargs)
        log.info("Using target profile: %s" % target.__class__.__name__)
        return target

    # Run the testimage task on a build while redirecting DEPLOY_DIR_IMAGE to repo.localdir, where the images are downloaded.
    def runTestimageBuild(self, image_type):
        log.info("Running the runtime tests for %s.." % image_type)
        postconfig = "DEPLOY_DIR_IMAGE = \"%s\"" % self.repo.localdir
        result = bitbake("%s -c testimage" % image_type, ignore_status=True, postconfig=postconfig)
        testimage_results = ftools.read_file(os.path.join(get_bb_var("T", image_type), "log.do_testimage"))
        log.info('Runtime tests results for %s:' % image_type)
        print(testimage_results)
        return result

    # Start the procedure!
    def run(self):
        if self.required_packages:
            # Build the required packages for the tests
            log.info("Building the required packages: %s ." % ', '.join(map(str, self.required_packages)))
            result = bitbake(self.required_packages, ignore_status=True)
            if result.status != 0:
                log.error("Could not build required packages: %s. Output: %s" % (self.required_packages, result.output))
                sys.exit(1)

            # Build the package repository meta data.
            log.info("Building the package index.")
            result = bitbake("package-index", ignore_status=True)
            if result.status != 0:
                log.error("Could not build 'package-index'. Output: %s" % result.output)
                sys.exit(1)

        # Create the directory structure for the images to be downloaded
        log.info("Creating directory structure %s" % self.repo.localdir)
        if not os.path.exists(self.repo.localdir):
            os.makedirs(self.repo.localdir)

        # For each image type, download the needed files and run the tests.
        noissuesfound = True
        for image_type in self.image_types:
            if self.skip_download:
                log.info("Skipping downloading the images..")
            else:
                target = self.get_target_profile(image_type)
                files_dict = target.get_files_dict()
                log.info("Downloading files for %s" % image_type)
                for f in files_dict:
                    if self.repo.check_old_file(files_dict[f]):
                        filepath = os.path.join(self.repo.localdir, files_dict[f])
                        if os.path.exists(filepath):
                            os.remove(filepath)
                        self.repo.fetch(files_dict[f])

            result = self.runTestimageBuild(image_type)
            if result.status != 0:
                noissuesfound = False

        if noissuesfound:
            log.info('Finished. No issues found.')
        else:
            log.error('Finished. Some runtime tests have failed. Returning non-0 status code.')
            sys.exit(1)



def main():

    parser = get_args_parser()
    args = parser.parse_args()

    hwauto = HwAuto(image_types=args.image_types, repolink=args.repo_link, required_packages=args.required_packages, targetprofile=args.targetprofile, repoprofile=args.repoprofile, skip_download=args.skip_download)

    hwauto.run()

if __name__ == "__main__":
    try:
        ret = main()
    except Exception:
        ret = 1
        import traceback
        traceback.print_exc()
    sys.exit(ret)