def validate(self): super(DockerAction, self).validate() which("docker") # Print docker version try: out = subprocess.check_output( ["docker", "version", "-f", "{{.Server.Version}}"]) out = out.decode("utf-8", errors="replace").strip("\n") self.logger.debug("docker server, installed at version: %s", out) out = subprocess.check_output( ["docker", "version", "-f", "{{.Client.Version}}"]) out = out.decode("utf-8", errors="replace").strip("\n") self.logger.debug("docker client, installed at version: %s", out) except subprocess.CalledProcessError as exc: raise InfrastructureError("Unable to call '%s': %s" % (exc.cmd, exc.output)) except OSError: raise InfrastructureError("Command 'docker' does not exist") # check docker image name # The string should be safe for command line inclusion image_name = self.parameters["image"] if re.compile("^[a-z0-9._:/-]+$").match(image_name) is None: self.errors = "image_name '%s' is invalid" % image_name self.set_namespace_data(action=self.name, label='image', key='name', value=image_name)
def validate(self): super().validate() persist = self.parameters.get("persistent_nfs") if not persist: return if "address" not in persist: self.errors = "Missing address for persistent NFS" return if ":" not in persist["address"]: self.errors = ("Unrecognised NFS URL: '%s'" % self.parameters["persistent_nfs"]["address"]) return nfs_server, dirname = persist["address"].split(":") which("rpcinfo") self.errors = rpcinfo_nfs(nfs_server) self.set_namespace_data(action=self.name, label="nfs_address", key="nfsroot", value=dirname) self.set_namespace_data(action=self.name, label="nfs_address", key="serverip", value=nfs_server) self.job.device["dynamic_data"]["NFS_ROOTFS"] = dirname self.job.device["dynamic_data"]["NFS_SERVER_IP"] = nfs_server
def validate(self): super().validate() if not self.parameters.get("ramdisk"): # idempotency return if not self.parameters["ramdisk"].get( "install_modules", True ) and not self.parameters["ramdisk"].get("install_overlay", True): self.skip = True return if "parameters" in self.job.device["actions"]["deploy"]: self.add_header = self.job.device["actions"]["deploy"]["parameters"].get( "add_header" ) if self.add_header is not None: if self.add_header == "u-boot": which("mkimage") if ( "mkimage_arch" not in self.job.device["actions"]["deploy"]["parameters"] ): self.errors = "Missing architecture for uboot mkimage support (mkimage_arch in deploy parameters)" return self.mkimage_arch = self.job.device["actions"]["deploy"][ "parameters" ]["mkimage_arch"] else: self.errors = "ramdisk: add_header: unknown header type"
def validate(self): super(UBootPrepareKernelAction, self).validate() if 'parameters' not in self.job.device['actions']['deploy']: return self.params = self.job.device['actions']['deploy']['parameters'] self.kernel_type = self.get_namespace_data( action='download-action', label='type', key='kernel' ) self.bootcommand = None if 'parameters' not in self.job.device: if self.kernel_type: self.errors = "Kernel boot type is not supported by this device." if self.kernel_type: self.set_namespace_data(action=self.name, label='prepared-kernel', key='exists', value=True) self.bootcommand = map_kernel_uboot(self.kernel_type, self.job.device.get('parameters', None)) self.kernel_type = str(self.kernel_type).lower() if self.bootcommand not in self.job.device['parameters']: self.errors = "Requested kernel boot type '%s' is not supported by this device." % self.bootcommand if self.kernel_type == "bootm" or self.kernel_type == "bootz" or self.kernel_type == "booti": self.errors = "booti, bootm and bootz are deprecated, please use 'image', 'uimage' or 'zimage'" which('mkimage') if 'mkimage_arch' not in self.params: self.errors = "Missing architecture for uboot mkimage support (mkimage_arch in u-boot parameters)" if self.bootcommand == 'bootm' and self.kernel_type != 'uimage': self.mkimage_conversion = True self.set_namespace_data( action='uboot-prepare-kernel', label='bootcommand', key='bootcommand', value=self.bootcommand)
def validate(self): super().validate() boot = self.job.device['actions']['boot']['methods']['pyocd'] pyocd_binary = boot['parameters']['command'] which(pyocd_binary) self.base_command = [pyocd_binary] self.base_command.extend(boot['parameters'].get('options', [])) if self.job.device['board_id'] == '0000000000': self.errors = "[PYOCD] board_id unset" substitutions = {} self.base_command.extend(['--board', self.job.device['board_id']]) for action in self.get_namespace_keys('download-action'): pyocd_full_command = [] image_arg = self.get_namespace_data(action='download-action', label=action, key='image_arg') action_arg = self.get_namespace_data(action='download-action', label=action, key='file') if image_arg: if not isinstance(image_arg, str): self.errors = "image_arg is not a string (try quoting it)" continue substitutions["{%s}" % action] = action_arg pyocd_full_command.extend(self.base_command) pyocd_full_command.extend( substitute([image_arg], substitutions)) self.exec_list.append(pyocd_full_command) else: pyocd_full_command.extend(self.base_command) pyocd_full_command.extend([action_arg]) self.exec_list.append(pyocd_full_command) if len(self.exec_list) < 1: self.errors = "No PyOCD command to execute"
def validate(self): super().validate() if 'parameters' not in self.job.device['actions']['deploy']: return self.params = self.job.device['actions']['deploy']['parameters'] self.kernel_type = self.get_namespace_data(action='download-action', label='type', key='kernel') self.bootcommand = None if 'parameters' not in self.job.device: if self.kernel_type: self.errors = "Kernel boot type is not supported by this device." if self.kernel_type: self.set_namespace_data(action=self.name, label='prepared-kernel', key='exists', value=True) self.bootcommand = map_kernel_uboot( self.kernel_type, self.job.device.get('parameters')) self.kernel_type = str(self.kernel_type).lower() if self.bootcommand not in self.job.device['parameters']: self.errors = "Requested kernel boot type '%s' is not supported by this device." % self.bootcommand if self.kernel_type == "bootm" or self.kernel_type == "bootz" or self.kernel_type == "booti": self.errors = "booti, bootm and bootz are deprecated, please use 'image', 'uimage' or 'zimage'" which('mkimage') if 'mkimage_arch' not in self.params: self.errors = "Missing architecture for uboot mkimage support (mkimage_arch in u-boot parameters)" if self.bootcommand == 'bootm' and self.kernel_type != 'uimage': self.mkimage_conversion = True self.set_namespace_data(action='uboot-prepare-kernel', label='bootcommand', key='bootcommand', value=self.bootcommand)
def validate(self): super(TftpAction, self).validate() if 'kernel' not in self.parameters: self.errors = "%s needs a kernel to deploy" % self.name if not self.valid: return if 'nfs_url' in self.parameters: self.errors = "Use a persistent_nfs dictionary instead of nfs_url" if 'nfsrootfs' in self.parameters and 'persistent_nfs' in self.parameters: self.errors = "Only one of nfsrootfs or persistent_nfs can be specified" # Extract the 3 last path elements. See action.mkdtemp() suffix = os.path.join(*self.tftp_dir.split('/')[-2:]) self.set_namespace_data(action=self.name, label='tftp', key='suffix', value=suffix) which('in.tftpd') # Check that the tmp directory is in the tftpd_dir or in /tmp for the # unit tests tftpd_directory = os.path.realpath(tftpd_dir()) tftp_dir = os.path.realpath(self.tftp_dir) tmp_dir = tempfile.gettempdir() if not tftp_dir.startswith(tftpd_directory) and \ not tftp_dir.startswith(tmp_dir): self.errors = "tftpd directory is not configured correctly, see /etc/default/tftpd-hpa"
def validate(self): super(FlashPyOCDAction, self).validate() boot = self.job.device['actions']['boot']['methods']['pyocd'] pyocd_binary = boot['parameters']['command'] which(pyocd_binary) self.base_command = [pyocd_binary] self.base_command.extend(boot['parameters'].get('options', [])) if self.job.device['board_id'] == '0000000000': self.errors = "board_id unset" substitutions = {} self.base_command.extend(['--board', self.job.device['board_id']]) namespace = self.parameters['namespace'] for action in self.data[namespace]['download-action'].keys(): pyocd_full_command = [] image_arg = self.get_namespace_data(action='download-action', label=action, key='image_arg') action_arg = self.get_namespace_data(action='download-action', label=action, key='file') if image_arg: if not isinstance(image_arg, str): self.errors = "image_arg is not a string (try quoting it)" continue substitutions["{%s}" % action] = action_arg pyocd_full_command.extend(self.base_command) pyocd_full_command.extend(substitute([image_arg], substitutions)) self.exec_list.append(pyocd_full_command) else: pyocd_full_command.extend(self.base_command) pyocd_full_command.extend([action_arg]) self.exec_list.append(pyocd_full_command) if len(self.exec_list) < 1: self.errors = "No PyOCD command to execute"
def validate(self): super(NbdAction, self).validate() if 'kernel' not in self.parameters: self.errors = "%s needs a kernel to deploy" % self.name if not self.valid: return if 'nbdroot' not in self.parameters: self.errors = "NBD deployment needs a 'nbdroot' parameter" if 'initrd' not in self.parameters: self.errors = "NBD deployment needs an 'initrd' parameter" # we cannot work with these when using nbd if 'nfsrootfs' in self.parameters or 'nfs_url' in self.parameters: self.errors = "nfsrootfs or nfs_url cannot be used with NBD deployment, use a e.g. ext3/4 filesystem as 'nbdroot=' parameter" if 'ramdisk' in self.parameters: self.errors = "ramdisk cannot be used with NBD deployment, use a e.g. ext3/4 filesystem as 'initrd' parameter" # Extract the 3 last path elements. See action.mkdtemp() suffix = os.path.join(*self.tftp_dir.split('/')[-2:]) self.set_namespace_data(action="tftp-deploy", label='tftp', key='suffix', value=suffix) # we need tftp _and_ xnbd-server which('in.tftpd') which('xnbd-server') # Check that the tmp directory is in the nbdd_dir or in /tmp for the # unit tests tftpd_directory = os.path.realpath(tftpd_dir()) tftp_dir = os.path.realpath(self.tftp_dir) tmp_dir = tempfile.gettempdir() if not tftp_dir.startswith(tftpd_directory) and \ not tftp_dir.startswith(tmp_dir): self.errors = "tftpd directory is not configured correctly, see /etc/default/tftpd-hpa"
def validate(self): super(Scp, self).validate() params = self._check_params() which('scp') if 'ssh' not in self.job.device['actions']['deploy']['methods']: self.errors = "Unable to use %s without ssh deployment" % self.name if 'ssh' not in self.job.device['actions']['boot']['methods']: self.errors = "Unable to use %s without ssh boot" % self.name if self.get_namespace_data(action='prepare-scp-overlay', label="prepare-scp-overlay", key=self.key): self.primary = False elif 'host' not in self.job.device['actions']['deploy']['methods'][ 'ssh']: self.errors = "Invalid device or job configuration, missing host." if not self.primary and len( self.get_namespace_data(action='prepare-scp-overlay', label="prepare-scp-overlay", key=self.key)) != 1: self.errors = "Invalid number of host_keys" if self.primary: host_address = self.job.device['actions']['deploy']['methods'][ 'ssh']['host'] if not host_address: self.errors = "Unable to retrieve ssh_host address for primary connection." if 'port' in self.job.device['actions']['deploy']['methods']['ssh']: port = str( self.job.device['actions']['deploy']['methods']['ssh']['port']) if not port.isdigit(): self.errors = "Port was set but was not a digit" if self.valid: self.scp.append('scp') if 'options' in params: self.scp.extend(params['options'])
def _check_command(self): exe = '' try: exe = self.command.split(' ')[0] except AttributeError: self.errors = "Unable to parse the connection command %s" % self.command which(exe)
def validate(self): super().validate() suffix = os.path.join(*self.preseed_path.split("/")[-2:]) self.set_namespace_data( action=self.name, label="iso", key="suffix", value=suffix ) which("in.tftpd")
def validate(self): super().validate() if 'kernel' not in self.parameters: self.errors = "%s needs a kernel to deploy" % self.name if not self.valid: return if 'nbdroot' not in self.parameters: self.errors = "NBD deployment needs a 'nbdroot' parameter" if 'initrd' not in self.parameters: self.errors = "NBD deployment needs an 'initrd' parameter" # we cannot work with these when using nbd if 'nfsrootfs' in self.parameters or 'nfs_url' in self.parameters: self.errors = "nfsrootfs or nfs_url cannot be used with NBD deployment, use a e.g. ext3/4 filesystem as 'nbdroot=' parameter" if 'ramdisk' in self.parameters: self.errors = "ramdisk cannot be used with NBD deployment, use a e.g. ext3/4 filesystem as 'initrd' parameter" # Extract the 3 last path elements. See action.mkdtemp() suffix = os.path.join(*self.tftp_dir.split('/')[-2:]) self.set_namespace_data(action="tftp-deploy", label='tftp', key='suffix', value=suffix) # we need tftp _and_ xnbd-server which('in.tftpd') which('xnbd-server') # Check that the tmp directory is in the nbdd_dir or in /tmp for the # unit tests tftpd_directory = os.path.realpath(tftpd_dir()) tftp_dir = os.path.realpath(self.tftp_dir) tmp_dir = tempfile.gettempdir() if not tftp_dir.startswith(tftpd_directory) and \ not tftp_dir.startswith(tmp_dir): self.errors = "tftpd directory is not configured correctly, see /etc/default/tftpd-hpa"
def _check_command(self): exe = '' try: exe = self.command.split(' ')[0] except AttributeError: self.errors = "Unable to parse the connection command %s" % self.command which(exe)
def validate(self): if "lxc" not in self.job.device["actions"]["boot"]["methods"]: return super().validate() which("lxc-attach") if "lxc" not in self.job.device["actions"]["boot"]["connections"]: self.errors = "Device not configured to support LXC connection."
def validate(self): super().validate() suffix = os.path.join(*self.preseed_path.split('/')[-2:]) self.set_namespace_data(action=self.name, label='iso', key='suffix', value=suffix) which('in.tftpd')
def validate(self): if "adb" not in self.job.device["actions"]["boot"]["methods"]: return if "adb_serial_number" not in self.job.device: self.errors = "device adb serial number missing" if "adb" not in self.job.device["actions"]["boot"]["connections"]: self.errors = "Device not configured to support adb connection." super().validate() which("adb")
def validate(self): super().validate() which("bmaptool") self.params = self.job.device["actions"]["boot"]["methods"][ self.parameters["method"] ]["parameters"] if self.params.get("uboot_mass_storage_device", False): self.ums_device = self.params["uboot_mass_storage_device"] else: raise JobError("uboot_mass_storage_device is not set")
def validate(self): super(LxcAction, self).validate() self.logger.info("lxc, installed at version: %s", debian_package_version(pkg='lxc', split=False)) protocols = [protocol.name for protocol in self.job.protocols] if LxcProtocol.name not in protocols: self.logger.debug("Missing protocol '%s' in %s", LxcProtocol.name, protocols) self.errors = "Missing protocol '%s'" % LxcProtocol.name which('lxc-create')
def validate(self): super().validate() which("mkimage") self.deploy_params = self.job.device["actions"]["deploy"].get( "parameters", dict()) device_params = self.job.device.get("parameters") if device_params is None: self.errors = "Missing device parameters" elif "load_address" not in device_params: self.errors = "Missing load_address from device parameters" else: self.device_params = device_params
def validate(self): super().validate() lxc_version = debian_package_version(pkg='lxc', split=False) if lxc_version is not '': self.logger.info("lxc, installed at version: %s", lxc_version) else: self.logger.info( "lava-lxc-mocker, installed at version: %s", debian_package_version(pkg='lava-lxc-mocker', split=False)) protocols = [protocol.name for protocol in self.job.protocols] if LxcProtocol.name not in protocols: self.logger.debug("Missing protocol '%s' in %s", LxcProtocol.name, protocols) self.errors = "Missing protocol '%s'" % LxcProtocol.name which('lxc-create')
def cpio(directory, filename): which("cpio") which("find") with chdir(directory): try: find = subprocess.check_output(["find", "."], stderr=subprocess.STDOUT) # nosec return subprocess.check_output( # nosec ["cpio", "--create", "--format", "newc", "--file", filename], input=find, stderr=subprocess.STDOUT, ).decode("utf-8", errors="replace") except Exception as exc: raise InfrastructureError("Unable to create cpio archive %r: %s" % (filename, exc))
def validate(self): super(QemuCommandLine, self).validate() boot = self.job.device['actions']['boot']['methods']['qemu'] qemu_binary = which(boot['parameters']['command']) self.sub_command = [qemu_binary] self.sub_command.extend(boot['parameters'].get('options', [])) boot_opts = boot['parameters'].get('boot_options', None) if boot_opts: self.console = "console=%s" % boot_opts['console'] self.boot_order = "-boot %s" % boot_opts['boot_order'] if not qemu_binary or not self.console or not self.boot_order: self.errors = "Invalid parameters for %s" % self.name # create the preseed.cfg url # needs to be an IP address for DI, DNS is not available. # PRESEED_URL='http://10.15.0.32/tmp/d-i/jessie/preseed.cfg' ip_addr = dispatcher_ip(self.job.parameters['dispatcher']) self.preseed_url = 'tftp://%s/' % ip_addr self.sub_command.append(' -drive format=raw,file={emptyimage} ') self.sub_command.append(self.boot_order) self.command_line = " -append '%s console=tty0 console=tty1 %s %s %s %s preseed/url=%s{preseed} --- %s ' " % ( self.parameters['deployment_data']['base'], self.parameters['deployment_data']['locale'], self.console, self.parameters['deployment_data']['keymaps'], self.parameters['deployment_data']['netcfg'], self.preseed_url, self.console) self.set_namespace_data(action=self.name, label=self.name, key='prompts', value=self.parameters['deployment_data']['prompts']) self.set_namespace_data(action=self.name, label=self.name, key='append', value=self.command_line)
def validate(self): super(PersistentNFSOverlay, self).validate() persist = self.parameters.get('persistent_nfs', None) if not persist: return if 'address' not in persist: self.errors = "Missing address for persistent NFS" return if ':' not in persist['address']: self.errors = "Unrecognised NFS URL: '%s'" % self.parameters['persistent_nfs']['address'] return nfs_server, dirname = persist['address'].split(':') which('rpcinfo') self.errors = rpcinfo_nfs(nfs_server) self.set_namespace_data(action=self.name, label='nfs_address', key='nfsroot', value=dirname) self.set_namespace_data(action=self.name, label='nfs_address', key='serverip', value=nfs_server)
def validate(self): super().validate() boot = self.job.device["actions"]["boot"]["methods"]["pyocd"] pyocd_binary = boot["parameters"]["command"] binary = which(pyocd_binary) self.logger.info(binary_version(binary, "--version")) self.base_command = [pyocd_binary] self.base_command.extend(boot["parameters"].get("options", [])) if self.job.device["board_id"] == "0000000000": self.errors = "[PYOCD] board_id unset" substitutions = {} self.base_command.extend(["--board", self.job.device["board_id"]]) for action in self.get_namespace_keys("download-action"): pyocd_full_command = [] image_arg = self.get_namespace_data(action="download-action", label=action, key="image_arg") action_arg = self.get_namespace_data(action="download-action", label=action, key="file") if image_arg: if not isinstance(image_arg, str): self.errors = "image_arg is not a string (try quoting it)" continue substitutions["{%s}" % action] = action_arg pyocd_full_command.extend(self.base_command) pyocd_full_command.extend( substitute([image_arg], substitutions)) self.exec_list.append(pyocd_full_command) else: pyocd_full_command.extend(self.base_command) pyocd_full_command.extend([action_arg]) self.exec_list.append(pyocd_full_command) if not self.exec_list: self.errors = "No PyOCD command to execute"
def validate(self): super(ConnectSsh, self).validate() params = self._check_params() which('ssh') if 'host' in self.job.device['actions']['deploy']['methods']['ssh']: self.primary = True self.host = self.job.device['actions']['deploy']['methods']['ssh']['host'] if self.valid: self.command = ['ssh'] if 'options' in params: self.command.extend(params['options']) # add arguments to ignore host key checking of the host device self.command.extend(['-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no']) if self.identity_file: # add optional identity file self.command.extend(['-i', self.identity_file]) self.command.extend(self.ssh_port)
def validate(self): super().validate() which("docker") options = self.job.device["actions"]["deploy"]["methods"]["docker"]["options"] if options["remote"]: self.remote = ["--host"] + [options["remote"]] # Print docker version try: out = subprocess.check_output( # nosec - internal ["docker"] + self.remote + ["version", "-f", "{{.Server.Version}}"] ) out = out.decode("utf-8", errors="replace").strip("\n") self.logger.debug("docker server, installed at version: %s", out) out = subprocess.check_output( # nosec - internal ["docker", "version", "-f", "{{.Client.Version}}"] ) out = out.decode("utf-8", errors="replace").strip("\n") self.logger.debug("docker client, installed at version: %s", out) except subprocess.CalledProcessError as exc: raise InfrastructureError("Unable to call '%s': %s" % (exc.cmd, exc.output)) except OSError: raise InfrastructureError("Command 'docker' does not exist") # "image" can be a dict or a string image = self.parameters["image"] if isinstance(image, str): self.image_name = image self.local = False else: self.image_name = image["name"] self.local = image.get("local", False) # check docker image name # The string should be safe for command line inclusion if ( re.compile( "^[a-z0-9]+[a-z0-9._/-]*[a-z0-9]+(:[a-zA-Z0-9_]+[a-zA-Z0-9._-]*)?$" ).match(self.image_name) is None ): self.errors = "image name '%s' is invalid" % self.image_name self.set_namespace_data( action=self.name, label="image", key="name", value=self.image_name )
def uncpio(filename, directory): which("cpio") with chdir(directory): try: subprocess.check_output( # nosec [ "cpio", "--extract", "--make-directories", "--unconditional", "--file", filename, ], stderr=subprocess.STDOUT, ) except subprocess.SubprocessError as exc: raise InfrastructureError("Unable to extract cpio archive %r: %s" % (filename, exc))
def compress_file(infile, compression): if not compression: return infile if compression not in compress_command_map.keys(): raise JobError("Cannot find shell command to compress: %s" % compression) # Check that the command does exists which(compress_command_map[compression][0]) with chdir(os.path.dirname(infile)): # local copy for idempotency cmd = compress_command_map[compression][:] cmd.append(infile) try: subprocess.check_output(cmd) # nosec - internal use. return "%s.%s" % (infile, compression) except (OSError, subprocess.CalledProcessError) as exc: raise InfrastructureError("unable to compress file %s: %s" % (infile, exc))
def validate(self): super().validate() if "kernel" not in self.parameters: self.errors = "%s needs a kernel to deploy" % self.name if not self.valid: return if "nfsrootfs" in self.parameters and "persistent_nfs" in self.parameters: self.errors = "Only one of nfsrootfs or persistent_nfs can be specified" which("in.tftpd") # Check that the tmp directory is in the tftpd_dir or in /tmp for the # unit tests tftpd_directory = os.path.realpath(filesystem.tftpd_dir()) tftp_dir = os.path.realpath(self.tftp_dir) tmp_dir = tempfile.gettempdir() if not tftp_dir.startswith( tftpd_directory) and not tftp_dir.startswith(tmp_dir): self.errors = "tftpd directory is not configured correctly, see /etc/default/tftpd-hpa"
def validate(self): super().validate() which("mkimage") deploy_params = self.job.device["actions"]["deploy"].get("parameters") if deploy_params is None: self.errors = "Missing parameters in deploy action" elif "mkimage_arch" not in deploy_params: self.errors = "Missing mkimage_arch parameter for FIT support" else: self.deploy_params = deploy_params device_params = self.job.device.get("parameters") if device_params is None: self.errors = "Missing device parameters" elif "load_address" not in device_params: self.errors = "Missing load_address from device parameters" else: self.device_params = device_params
def compress_file(infile, compression): if not compression: return infile if compression not in compress_command_map.keys(): raise JobError("Cannot find shell command to compress: %s" % compression) # Check that the command does exists which(compress_command_map[compression].split(" ")[0]) with chdir(os.path.dirname(infile)): cmd = "%s %s" % (compress_command_map[compression], infile) try: # safe to use shell=True here, no external arguments subprocess.check_output(cmd, shell=True) return "%s.%s" % (infile, compression) except (OSError, subprocess.CalledProcessError) as exc: raise InfrastructureError('unable to compress file %s: %s' % (infile, exc))
def validate(self): super(PrepareFITAction, self).validate() which('mkimage') deploy_params = self.job.device['actions']['deploy'].get('parameters') if deploy_params is None: self.errors = "Missing parameters in deploy action" elif 'mkimage_arch' not in deploy_params: self.errors = "Missing mkimage_arch parameter for FIT support" else: self.deploy_params = deploy_params device_params = self.job.device.get('parameters') if device_params is None: self.errors = "Missing device parameters" elif 'load_address' not in device_params: self.errors = "Missing load_address from device parameters" else: self.device_params = device_params
def validate(self): super(CompressRamdisk, self).validate() if not self.parameters.get('ramdisk', None): # idempotency return if not self.parameters['ramdisk'].get('install_modules', True) and \ not self.parameters['ramdisk'].get('install_overlay', True): self.skip = True return if 'parameters' in self.job.device['actions']['deploy']: self.add_header = self.job.device['actions']['deploy']['parameters'].get('add_header', None) if self.add_header is not None: if self.add_header == 'u-boot': which('mkimage') if 'mkimage_arch' not in self.job.device['actions']['deploy']['parameters']: self.errors = "Missing architecture for uboot mkimage support (mkimage_arch in deploy parameters)" return self.mkimage_arch = self.job.device['actions']['deploy']['parameters']['mkimage_arch'] else: self.errors = "ramdisk: add_header: unknown header type"
def validate(self): super().validate() which('mkimage') deploy_params = self.job.device['actions']['deploy'].get('parameters') if deploy_params is None: self.errors = "Missing parameters in deploy action" elif 'mkimage_arch' not in deploy_params: self.errors = "Missing mkimage_arch parameter for FIT support" else: self.deploy_params = deploy_params device_params = self.job.device.get('parameters') if device_params is None: self.errors = "Missing device parameters" elif 'load_address' not in device_params: self.errors = "Missing load_address from device parameters" else: self.device_params = device_params
def validate(self): super().validate() params = self._check_params() which("scp") if "ssh" not in self.job.device["actions"]["deploy"]["methods"]: self.errors = "Unable to use %s without ssh deployment" % self.name if "ssh" not in self.job.device["actions"]["boot"]["methods"]: self.errors = "Unable to use %s without ssh boot" % self.name if self.get_namespace_data( action="prepare-scp-overlay", label="prepare-scp-overlay", key=self.key ): self.primary = False elif "host" not in self.job.device["actions"]["deploy"]["methods"]["ssh"]: self.errors = "Invalid device or job configuration, missing host." if ( not self.primary and len( self.get_namespace_data( action="prepare-scp-overlay", label="prepare-scp-overlay", key=self.key, ) ) != 1 ): self.errors = "Invalid number of host_keys" if self.primary: host_address = self.job.device["actions"]["deploy"]["methods"]["ssh"][ "host" ] if not host_address: self.errors = ( "Unable to retrieve ssh_host address for primary connection." ) if "port" in self.job.device["actions"]["deploy"]["methods"]["ssh"]: port = str(self.job.device["actions"]["deploy"]["methods"]["ssh"]["port"]) if not port.isdigit(): self.errors = "Port was set but was not a digit" if self.valid: self.scp.append("scp") if "options" in params: self.scp.extend(params["options"])
def validate(self): super(LxcCreateUdevRuleAction, self).validate() which('udevadm') if 'device_info' in self.job.device \ and not isinstance(self.job.device.get('device_info'), list): self.errors = "device_info unset" # If we are allowed to use a filesystem label, we don't require a board_id # By default, we do require a board_id (serial) requires_board_id = not allow_fs_label(self.job.device) try: if 'device_info' in self.job.device: for usb_device in self.job.device['device_info']: if usb_device.get('board_id', '') in ['', '0000000000'] \ and requires_board_id: self.errors = "board_id unset" if usb_device.get('usb_vendor_id', '') == '0000': self.errors = 'usb_vendor_id unset' if usb_device.get('usb_product_id', '') == '0000': self.errors = 'usb_product_id unset' except TypeError: self.errors = "Invalid parameters for %s" % self.name
def validate(self): """ The unit test skips if schroot is not installed, the action marks the pipeline as invalid if schroot is not installed. """ if "schroot" not in self.parameters: return if "schroot" not in self.job.device["actions"]["boot"]["methods"]: self.errors = "No schroot support in device boot methods" return which("schroot") # device parameters are for ssh params = self.job.device["actions"]["boot"]["methods"] if "command" not in params["schroot"]: self.errors = "Missing schroot command in device configuration" return if "name" not in params["schroot"]: self.errors = "Missing schroot name in device configuration" return self.schroot = params["schroot"]["name"] self.command = params["schroot"]["command"]
def validate(self): super(IsoRebootAction, self).validate() if 'prompts' not in self.parameters: self.errors = "Unable to identify boot prompts from job definition." try: boot = self.job.device['actions']['boot']['methods']['qemu'] qemu_binary = which(boot['parameters']['command']) self.sub_command = [qemu_binary] self.sub_command.extend(boot['parameters'].get('options', [])) except AttributeError as exc: raise ConfigurationError(exc) except (KeyError, TypeError): self.errors = "Invalid parameters for %s" % self.name
def validate(self): super(TftpAction, self).validate() if 'kernel' not in self.parameters: self.errors = "%s needs a kernel to deploy" % self.name if not self.valid: return if 'nfs_url' in self.parameters: self.errors = "Use a persistent_nfs dictionary instead of nfs_url" if 'nfsrootfs' in self.parameters and 'persistent_nfs' in self.parameters: self.errors = "Only one of nfsrootfs or persistent_nfs can be specified" # Extract the 3 last path elements. See action.mkdtemp() suffix = os.path.join(*self.tftp_dir.split('/')[-2:]) self.set_namespace_data(action=self.name, label='tftp', key='suffix', value=suffix) which('in.tftpd') # Check that the tmp directory is in the tftpd_dir or in /tmp for the # unit tests tftpd_directory = os.path.realpath(tftpd_dir()) tftp_dir = os.path.realpath(self.tftp_dir) tmp_dir = tempfile.gettempdir() if not tftp_dir.startswith(tftpd_directory) and \ not tftp_dir.startswith(tmp_dir): self.errors = "tftpd directory is not configured correctly, see /etc/default/tftpd-hpa"
def validate(self): super(DockerAction, self).validate() which("docker") # Print docker version try: out = subprocess.check_output(["docker", "version", "-f", "{{.Server.Version}}"]) out = out.decode("utf-8", errors="replace").strip("\n") self.logger.debug("docker server, installed at version: %s", out) out = subprocess.check_output(["docker", "version", "-f", "{{.Client.Version}}"]) out = out.decode("utf-8", errors="replace").strip("\n") self.logger.debug("docker client, installed at version: %s", out) except subprocess.CalledProcessError as exc: raise InfrastructureError("Unable to call '%s': %s" % (exc.cmd, exc.output)) except OSError: raise InfrastructureError("Command 'docker' does not exist") # check docker image name # The string should be safe for command line inclusion image_name = self.parameters["image"] if re.compile("^[a-z0-9._:/-]+$").match(image_name) is None: self.errors = "image_name '%s' is invalid" % image_name self.set_namespace_data(action=self.name, label='image', key='name', value=image_name)
def validate(self): super(FlashDFUAction, self).validate() try: boot = self.job.device['actions']['boot']['methods']['dfu'] dfu_binary = which(boot['parameters']['command']) self.base_command = [dfu_binary] self.base_command.extend(boot['parameters'].get('options', [])) if self.job.device['board_id'] == '0000000000': self.errors = "board_id unset" if self.job.device['usb_vendor_id'] == '0000': self.errors = 'usb_vendor_id unset' if self.job.device['usb_product_id'] == '0000': self.errors = 'usb_product_id unset' self.usb_vendor_id = self.job.device['usb_vendor_id'] self.usb_product_id = self.job.device['usb_product_id'] self.board_id = self.job.device['board_id'] self.base_command.extend(['--serial', self.board_id]) self.base_command.extend(['--device', '%s:%s' % (self.usb_vendor_id, self.usb_product_id)]) except AttributeError as exc: raise ConfigurationError(exc) except (KeyError, TypeError): self.errors = "Invalid parameters for %s" % self.name substitutions = {} namespace = self.parameters['namespace'] for action in self.data[namespace]['download-action'].keys(): dfu_full_command = [] image_arg = self.data[namespace]['download-action'][action].get('image_arg', None) action_arg = self.data[namespace]['download-action'][action].get('file', None) if not image_arg or not action_arg: self.errors = "Missing image_arg for %s. " % action continue if not isinstance(image_arg, str): self.errors = "image_arg is not a string (try quoting it)" continue substitutions["{%s}" % action] = action_arg dfu_full_command.extend(self.base_command) dfu_full_command.extend(substitute([image_arg], substitutions)) self.exec_list.append(dfu_full_command) if len(self.exec_list) < 1: self.errors = "No DFU command to execute"
def validate(self): if 'lxc' not in self.job.device['actions']['boot']['methods']: return super(ConnectLxc, self).validate() which('lxc-attach')
def validate(self): super(CallQemuAction, self).validate() # 'arch' must be defined in job definition context. try: if self.job.parameters['context']['arch'] not in \ self.job.device['available_architectures']: self.errors = "Non existing architecture specified in context arch parameter. Please check the device configuration for available options." return except KeyError: self.errors = "Arch parameter must be set in the context section. Please check the device configuration for available architectures." return if self.job.parameters['context']['arch'] in ['amd64', 'x86_64']: self.logger.info("qemu-system-x86, installed at version: %s", debian_package_version(pkg='qemu-system-x86', split=False)) if self.job.parameters['context']['arch'] in ['arm64', 'arm', 'armhf', 'aarch64']: self.logger.info("qemu-system-arm, installed at version: %s", debian_package_version(pkg='qemu-system-arm', split=False)) if self.parameters['method'] in ['qemu', 'qemu-nfs']: if 'prompts' not in self.parameters: if self.test_has_shell(self.parameters): self.errors = "Unable to identify boot prompts from job definition." self.methods = self.job.device['actions']['boot']['methods'] method = self.parameters['method'] boot = self.methods['qemu'] if 'qemu' in self.methods else self.methods['qemu-nfs'] try: if 'parameters' not in boot or 'command' not in boot['parameters']: self.errors = "Invalid device configuration - missing parameters" elif not boot['parameters']['command']: self.errors = "No QEMU binary command found - missing context." qemu_binary = which(boot['parameters']['command']) self.sub_command = [qemu_binary] self.sub_command.extend(boot['parameters'].get('options', [])) self.sub_command.extend( ['%s' % item for item in boot['parameters'].get('extra', [])]) except AttributeError as exc: self.errors = "Unable to parse device options: %s %s" % ( exc, self.job.device['actions']['boot']['methods'][method]) except (KeyError, TypeError): self.errors = "Invalid parameters for %s" % self.name namespace = self.parameters['namespace'] for label in self.data[namespace]['download-action'].keys(): if label in ['offset', 'available_loops', 'uefi', 'nfsrootfs']: continue image_arg = self.get_namespace_data(action='download-action', label=label, key='image_arg') action_arg = self.get_namespace_data(action='download-action', label=label, key='file') if not image_arg or not action_arg: self.errors = "Missing image_arg for %s. " % label continue self.substitutions["{%s}" % label] = action_arg self.commands.append(image_arg) self.substitutions["{NFS_SERVER_IP}"] = dispatcher_ip(self.job.parameters['dispatcher']) self.sub_command.extend(substitute(self.commands, self.substitutions)) if not self.sub_command: self.errors = "No QEMU command to execute" uefi_dir = self.get_namespace_data(action='deployimages', label='image', key='uefi_dir') if uefi_dir: self.sub_command.extend(['-L', uefi_dir, '-monitor', 'none']) # Check for enable-kvm command line option in device configuration. if method not in self.job.device['actions']['boot']['methods']: self.errors = "Unknown boot method '%s'" % method return options = self.job.device['actions']['boot']['methods'][method]['parameters']['options'] if "-enable-kvm" in options: # Check if the worker has kvm enabled. if not os.path.exists(SYS_CLASS_KVM): self.errors = "Device configuration contains -enable-kvm option but kvm module is not enabled."
def validate(self): super(DeployIsoAction, self).validate() suffix = os.path.join(*self.preseed_path.split('/')[-2:]) self.set_namespace_data(action=self.name, label='iso', key='suffix', value=suffix) which('in.tftpd')
def validate(self): super(ApplyOverlaySparseImage, self).validate() which('simg2img') which('mount') which('umount') which('img2simg')
def validate(self): super(ApplyLxcOverlay, self).validate() which('tar') if not os.path.exists(self.lava_test_dir): self.errors = "Missing lava-test-runner: %s" % self.lava_test_dir
def validate(self): super(LxcStartAction, self).validate() which('lxc-start')
def validate(self): super(LxcStopAction, self).validate() which('lxc-stop')