def check_packages(ctx, config): """ Checks gitbuilder to determine if there are missing packages for this job. If there are missing packages, fail the job. """ for task in ctx.config['tasks']: if task.keys()[0] == 'buildpackages': log.info("Checking packages skipped because " "the task buildpackages was found.") return log.info("Checking packages...") os_type = ctx.config.get("os_type") sha1 = ctx.config.get("sha1") # We can only do this check if there are a defined sha1 and os_type # in the job config. if os_type and sha1: package = get_builder_project()("ceph", ctx.config) template = "Checking packages for os_type '{os}', " \ "flavor '{flav}' and ceph hash '{ver}'" log.info( template.format( os=package.os_type, flav=package.flavor, ver=package.sha1, ) ) if package.version: log.info("Found packages for ceph version {ver}".format( ver=package.version )) else: msg = "Packages for distro '{d}' and ceph hash '{ver}' not found" msg = msg.format( d=package.distro, ver=package.sha1, ) log.error(msg) # set the failure message and update paddles with the status ctx.summary["failure_reason"] = msg set_status(ctx.summary, "dead") report.try_push_job_info(ctx.config, dict(status='dead')) raise VersionNotFoundError(package.base_url) else: log.info( "Checking packages skipped, missing os_type '{os}' or ceph hash '{ver}'".format( os=os_type, ver=sha1, ) )
def _get_package_version(self): """ Look for, and parse, a file called 'version' in base_url. """ url = "{0}/version".format(self.base_url) log.info("Looking for package version: {0}".format(url)) # will loop and retry until a 200 is returned or the retry # limits are reached resp = _get_response(url, wait=self.job_config.get("wait_for_package", False)) if not resp.ok: raise VersionNotFoundError(url) version = resp.text.strip().lstrip('v') log.info("Found version: {0}".format(version)) return version
def _block_looking_for_package_version(remote, base_url, wait=False): """ Look for, and parse, a file called 'version' in base_url. :param remote: the teuthology.orchestra.remote.Remote object :param wait: wait forever for the file to show up. (default False) :returns: str -- the version e.g. '0.67-240-g67a95b9-1raring' :raises: VersionNotFoundError """ while True: r = remote.run( args=['wget', '-q', '-O-', base_url + '/version'], stdout=StringIO(), check_status=False, ) if r.exitstatus != 0: if wait: log.info('Package not there yet, waiting...') time.sleep(15) continue raise VersionNotFoundError(base_url) break version = r.stdout.getvalue().strip() return version
def task(ctx, config): """ Make sure the specified kernel is installed. This can be a branch, tag, or sha1 of ceph-client.git or a local kernel package. To install ceph-client.git branch (default: master):: kernel: branch: testing To install ceph-client.git tag:: kernel: tag: v3.18 To install ceph-client.git sha1:: kernel: sha1: 275dd19ea4e84c34f985ba097f9cddb539f54a50 To install from a koji build_id:: kernel: koji: 416058 To install from a koji task_id:: kernel: koji_task: 9678206 When installing from koji you also need to set the urls for koji hub and the koji root in your teuthology.yaml config file. These are shown below with their default values:: kojihub_url: http://koji.fedoraproject.org/kojihub kojiroot_url: http://kojipkgs.fedoraproject.org/packages When installing from a koji task_id you also need to set koji_task_url, which is the base url used to download rpms from koji task results:: koji_task_url: https://kojipkgs.fedoraproject.org/work/ To install local rpm (target should be an rpm system):: kernel: rpm: /path/to/appropriately-named.rpm To install local deb (target should be a deb system):: kernel: deb: /path/to/appropriately-named.deb For rpm: or deb: to work it should be able to figure out sha1 from local kernel package basename, see get_sha1_from_pkg_name(). This means that you can't for example install a local tag - package built with upstream {rpm,deb}-pkg targets won't have a sha1 in its name. If you want to schedule a run and use a local kernel package, you have to copy the package over to a box teuthology workers are running on and specify a path to the package on that box. All of the above will install a specified kernel on all targets. You can specify different kernels for each role or for all roles of a certain type (more specific roles override less specific, see normalize_config() for details):: kernel: client: tag: v3.0 osd: branch: btrfs_fixes client.1: branch: more_specific osd.3: branch: master To wait 3 minutes for hosts to reboot (default: 300):: kernel: timeout: 180 To enable kdb:: kernel: kdb: true :param ctx: Context :param config: Configuration """ if config is None: config = {} assert isinstance(config, dict), \ "task kernel only supports a dictionary for configuration" overrides = ctx.config.get('overrides', {}).get('kernel', {}) config, timeout = normalize_and_apply_overrides(ctx, config, overrides) validate_config(ctx, config) log.info('config %s, timeout %d' % (config, timeout)) need_install = {} # sha1 to dl, or path to rpm or deb need_version = {} # utsrelease or sha1 kdb = {} remove_old_kernels(ctx) for role, role_config in config.items(): # gather information about this remote (role_remote, ) = ctx.cluster.only(role).remotes.keys() system_type = role_remote.os.name if role_config.get('rpm') or role_config.get('deb'): # We only care about path - deb: vs rpm: is meaningless, # rpm: just happens to be parsed first. Nothing is stopping # 'deb: /path/to/foo.rpm' and it will work provided remote's # os.package_type is 'rpm' and vice versa. path = role_config.get('rpm') if not path: path = role_config.get('deb') sha1 = get_sha1_from_pkg_name(path) assert sha1, "failed to extract commit hash from path %s" % path if need_to_install(ctx, role, sha1): need_install[role] = path need_version[role] = sha1 elif role_config.get('sha1') == 'distro': version = need_to_install_distro(role_remote) if version: need_install[role] = 'distro' need_version[role] = version elif role_config.get("koji") or role_config.get('koji_task'): # installing a kernel from koji build_id = role_config.get("koji") task_id = role_config.get("koji_task") if role_remote.os.package_type != "rpm": msg = ("Installing a kernel from koji is only supported " "on rpm based systems. System type is {system_type}.") msg = msg.format(system_type=system_type) log.error(msg) ctx.summary["failure_reason"] = msg ctx.summary["status"] = "dead" raise ConfigError(msg) # FIXME: this install should probably happen somewhere else # but I'm not sure where, so we'll leave it here for now. install_package('koji', role_remote) if build_id: # get information about this build from koji build_info = get_koji_build_info(build_id, role_remote, ctx) version = "{ver}-{rel}.x86_64".format( ver=build_info["version"], rel=build_info["release"]) elif task_id: # get information about results of this task from koji task_result = get_koji_task_result(task_id, role_remote, ctx) # this is not really 'build_info', it's a dict of information # about the kernel rpm from the task results, but for the sake # of reusing the code below I'll still call it that. build_info = get_koji_task_rpm_info('kernel', task_result['rpms']) # add task_id so we can know later that we're installing # from a task and not a build. build_info["task_id"] = task_id version = build_info["version"] if need_to_install(ctx, role, version): need_install[role] = build_info need_version[role] = version else: builder = get_builder_project()( "kernel", role_config, ctx=ctx, remote=role_remote, ) sha1 = builder.sha1 log.debug('sha1 for {role} is {sha1}'.format(role=role, sha1=sha1)) ctx.summary['{role}-kernel-sha1'.format(role=role)] = sha1 if need_to_install(ctx, role, sha1): if teuth_config.use_shaman: version = builder.scm_version else: version = builder.version if not version: raise VersionNotFoundError(builder.base_url) need_install[role] = sha1 need_version[role] = version # enable or disable kdb if specified, otherwise do not touch if role_config.get('kdb') is not None: kdb[role] = role_config.get('kdb') if need_install: install_firmware(ctx, need_install) download_kernel(ctx, need_install) install_and_reboot(ctx, need_install) wait_for_reboot(ctx, need_version, timeout) enable_disable_kdb(ctx, kdb)
def assert_result(self): if len(self._result.json()) == 0: raise VersionNotFoundError(self._result.url)
def _upgrade_deb_packages(ctx, config, remote, debs): """ Upgrade project's packages on remote Debian host Before doing so, installs the project's GPG key, writes a sources.list file, and runs ``apt-get update``. :param ctx: the argparse.Namespace object :param config: the config dict :param remote: the teuthology.orchestra.remote.Remote object :param debs: the Debian packages to be installed :param branch: the branch of the project to be used """ # check for ceph release key r = remote.run( args=[ 'sudo', 'apt-key', 'list', run.Raw('|'), 'grep', 'Ceph', ], stdout=StringIO(), check_status=False, ) if r.stdout.getvalue().find('Ceph automated package') == -1: # if it doesn't exist, add it remote.run( args=[ 'wget', '-q', '-O-', 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc', run.Raw('|'), 'sudo', 'apt-key', 'add', '-', ], stdout=StringIO(), ) # get distro name and arch r = remote.run( args=['lsb_release', '-sc'], stdout=StringIO(), ) dist = r.stdout.getvalue().strip() r = remote.run( args=['arch'], stdout=StringIO(), ) arch = r.stdout.getvalue().strip() log.info("dist %s arch %s", dist, arch) # branch/tag/sha1 flavor flavor = 'basic' sha1 = config.get('sha1') branch = config.get('branch') tag = config.get('tag') uri = _get_uri(tag, branch, sha1) base_url = 'http://{host}/{proj}-deb-{dist}-{arch}-{flavor}/{uri}'.format( host=teuth_config.gitbuilder_host, proj=config.get('project', 'ceph'), dist=dist, arch=arch, flavor=flavor, uri=uri, ) log.info('Pulling from %s', base_url) # get package version string while True: r = remote.run( args=[ 'wget', '-q', '-O-', base_url + '/version', ], stdout=StringIO(), check_status=False, ) if r.exitstatus != 0: if config.get('wait_for_package'): log.info('Package not there yet, waiting...') time.sleep(15) continue raise VersionNotFoundError("%s/version" % base_url) version = r.stdout.getvalue().strip() log.info('Package version is %s', version) break remote.run( args=[ 'echo', 'deb', base_url, dist, 'main', run.Raw('|'), 'sudo', 'tee', '/etc/apt/sources.list.d/{proj}.list'.format( proj=config.get('project', 'ceph')), ], stdout=StringIO(), ) remote.run(args=['sudo', 'apt-get', 'update'], check_status=False) remote.run(args=[ 'sudo', 'DEBIAN_FRONTEND=noninteractive', 'apt-get', '-y', '--force-yes', '-o', run.Raw('Dpkg::Options::="--force-confdef"'), '-o', run.Raw('Dpkg::Options::="--force-confold"'), 'install', ] + ['%s=%s' % (d, version) for d in debs], )
def _update_deb_package_list_and_install(ctx, remote, debs, config): """ Runs ``apt-get update`` first, then runs ``apt-get install``, installing the requested packages on the remote system. TODO: split this into at least two functions. :param ctx: the argparse.Namespace object :param remote: the teuthology.orchestra.remote.Remote object :param debs: list of packages names to install :param config: the config dict """ # check for ceph release key r = remote.run( args=[ 'sudo', 'apt-key', 'list', run.Raw('|'), 'grep', 'Ceph', ], stdout=StringIO(), check_status=False, ) if r.stdout.getvalue().find('Ceph automated package') == -1: # if it doesn't exist, add it remote.run( args=[ 'wget', '-q', '-O-', 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc', run.Raw('|'), 'sudo', 'apt-key', 'add', '-', ], stdout=StringIO(), ) baseparms = _get_baseurlinfo_and_dist(ctx, remote, config) log.info("Installing packages: {pkglist} on remote deb {arch}".format( pkglist=", ".join(debs), arch=baseparms['arch'])) # get baseurl base_url = _get_baseurl(ctx, remote, config) log.info('Pulling from %s', base_url) # get package version string # FIXME this is a terrible hack. while True: r = remote.run( args=[ 'wget', '-q', '-O-', base_url + '/version', ], stdout=StringIO(), check_status=False, ) if r.exitstatus != 0: if config.get('wait_for_package'): log.info('Package not there yet, waiting...') time.sleep(15) continue raise VersionNotFoundError("%s/version" % base_url) version = r.stdout.getvalue().strip() log.info('Package version is %s', version) break remote.run( args=[ 'echo', 'deb', base_url, baseparms['dist'], 'main', run.Raw('|'), 'sudo', 'tee', '/etc/apt/sources.list.d/{proj}.list'.format( proj=config.get('project', 'ceph')), ], stdout=StringIO(), ) remote.run(args=['sudo', 'apt-get', 'update'], check_status=False) remote.run(args=[ 'sudo', 'DEBIAN_FRONTEND=noninteractive', 'apt-get', '-y', '--force-yes', '-o', run.Raw('Dpkg::Options::="--force-confdef"'), '-o', run.Raw('Dpkg::Options::="--force-confold"'), 'install', ] + ['%s=%s' % (d, version) for d in debs], ) ldir = _get_local_dir(config, remote) if ldir: for fyle in os.listdir(ldir): fname = "%s/%s" % (ldir, fyle) remote.run(args=['sudo', 'dpkg', '-i', fname], )
def process_role(ctx, config, timeout, role, role_config): need_install = None # sha1 to dl, or path to rpm or deb need_version = None # utsrelease or sha1 # gather information about this remote (role_remote,) = ctx.cluster.only(role).remotes.keys() system_type = role_remote.os.name if role_config.get('rpm') or role_config.get('deb'): # We only care about path - deb: vs rpm: is meaningless, # rpm: just happens to be parsed first. Nothing is stopping # 'deb: /path/to/foo.rpm' and it will work provided remote's # os.package_type is 'rpm' and vice versa. path = role_config.get('rpm') if not path: path = role_config.get('deb') sha1 = get_sha1_from_pkg_name(path) assert sha1, "failed to extract commit hash from path %s" % path if need_to_install(ctx, role, sha1): need_install = path need_version = sha1 elif role_config.get('sha1') == 'distro': version = need_to_install_distro(role_remote, role_config) if version: need_install = 'distro' need_version = version elif role_config.get("koji") or role_config.get('koji_task'): # installing a kernel from koji build_id = role_config.get("koji") task_id = role_config.get("koji_task") if role_remote.os.package_type != "rpm": msg = ( "Installing a kernel from koji is only supported " "on rpm based systems. System type is {system_type}." ) msg = msg.format(system_type=system_type) log.error(msg) ctx.summary["failure_reason"] = msg ctx.summary["status"] = "dead" raise ConfigError(msg) # FIXME: this install should probably happen somewhere else # but I'm not sure where, so we'll leave it here for now. install_package('koji', role_remote) if build_id: # get information about this build from koji build_info = get_koji_build_info(build_id, role_remote, ctx) version = "{ver}-{rel}.x86_64".format( ver=build_info["version"], rel=build_info["release"] ) elif task_id: # get information about results of this task from koji task_result = get_koji_task_result(task_id, role_remote, ctx) # this is not really 'build_info', it's a dict of information # about the kernel rpm from the task results, but for the sake # of reusing the code below I'll still call it that. build_info = get_koji_task_rpm_info( 'kernel', task_result['rpms'] ) # add task_id so we can know later that we're installing # from a task and not a build. build_info["task_id"] = task_id version = build_info["version"] if need_to_install(ctx, role, version): need_install = build_info need_version = version else: builder = get_builder_project()( "kernel", role_config, ctx=ctx, remote=role_remote, ) sha1 = builder.sha1 log.debug('sha1 for {role} is {sha1}'.format(role=role, sha1=sha1)) ctx.summary['{role}-kernel-sha1'.format(role=role)] = sha1 if need_to_install(ctx, role, sha1): if teuth_config.use_shaman: version = builder.scm_version else: version = builder.version if not version: raise VersionNotFoundError(builder.base_url) need_install = sha1 need_version = version if need_install: install_firmware(ctx, {role: need_install}) download_kernel(ctx, {role: need_install}) install_and_reboot(ctx, {role: need_install}, config) wait_for_reboot(ctx, {role: need_version}, timeout, config) # enable or disable kdb if specified, otherwise do not touch if role_config.get('kdb') is not None: kdb = role_config.get('kdb') enable_disable_kdb(ctx, {role: kdb})