def _ProcessMsu(self, msu_file): """Command used to process updates downloaded. This command will apply updates to an image. If the exit code for the parsed command is anything other than zero, report fatal error. Args: msu_file: current file location. Raises: ActionError: Error during update application. """ scratch_dir = '%s\\Updates\\' % constants.SYS_CACHE # create scratch directory file_util.CreateDirectories(scratch_dir) logging.info('Applying %s image to main disk.', msu_file) # Apply updates to image try: execute.execute_binary(constants.WINPE_DISM, [ '/image:c:\\', '/Add-Package' f'/PackagePath:{msu_file}' f'/ScratchDir:{scratch_dir}' ], shell=True) except execute.Error as e: raise ActionError('Failed to process update %s: %s' % (msu_file, e))
def StartShell(self): """Start the PowerShell interpreter.""" try: execute.execute_binary(_Powershell(), ['-NoProfile', '-NoLogo'], shell=self.shell, log=self.log) except execute.Error as e: raise PowerShellError(str(e))
def test_execute_binary_return_codes(self, popen): popen_instance = popen.return_value popen_instance.returncode = 1337 popen_instance.stdout = io.BytesIO(b'foo\nbar') execute.execute_binary(r'C:\foo.exe', return_codes=[1337, 1338]) popen.assert_called_with([r'C:\foo.exe'], stdout=execute.subprocess.PIPE, stderr=execute.subprocess.STDOUT, universal_newlines=True)
def test_execute_binary_no_args(self, popen): popen_instance = popen.return_value popen_instance.returncode = 0 popen_instance.stdout = io.BytesIO(b'foo\nbar') execute.execute_binary(self.binary) popen.assert_called_with([self.binary], shell=False, stdout=execute.subprocess.PIPE, stderr=execute.subprocess.STDOUT, universal_newlines=True)
def test_execute_binary_silent(self, popen, i): popen_instance = popen.return_value popen_instance.returncode = 0 popen_instance.stdout = io.BytesIO(b'foo\nbar') execute.execute_binary(r'C:\foo.exe', log=False) i.assert_called_with('Executing: %s', r'C:\foo.exe') popen.assert_called_with([r'C:\foo.exe'], stdout=execute.subprocess.PIPE, stderr=execute.subprocess.STDOUT, universal_newlines=True)
def test_execute_binary_shell(self, popen, i): popen_instance = popen.return_value popen_instance.returncode = 0 popen_instance.stdout = io.BytesIO(b'foo\nbar') execute.execute_binary(self.binary, shell=True) i.assert_called_with('Executing: %s', self.binary) popen.assert_called_with([self.binary], shell=True, stdout=None, stderr=None, universal_newlines=True)
def test_execute_binary_silent(self, popen, i): popen_instance = popen.return_value popen_instance.returncode = 0 popen_instance.stdout = io.BytesIO(b'foo\nbar') execute.execute_binary(self.binary, log=False) i.assert_not_called() popen.assert_called_with([self.binary], shell=False, stdout=execute.subprocess.PIPE, stderr=execute.subprocess.STDOUT, universal_newlines=True) self.assertTrue(popen_instance.wait.called)
def test_execute_binary(self, popen, i): popen_instance = popen.return_value popen_instance.returncode = 0 popen_instance.stdout = io.BytesIO(b'foo\n\n\n') execute.execute_binary(self.binary, ['arg1', 'arg2']) i.assert_has_calls([ mock.call('Executing: %s', 'C:\\foo.exe arg1 arg2'), mock.call(b'foo') ], ) popen.assert_called_with([self.binary, 'arg1', 'arg2'], shell=False, stdout=execute.subprocess.PIPE, stderr=execute.subprocess.STDOUT, universal_newlines=True)
def _Run(self, command: Text, success_codes: List[int], reboot_codes: List[int], restart_retry: bool, shell: bool): logging.debug('Interpreting command: %s', command) try: command_cache = cache.Cache().CacheFromLine(command, self._build_info) except cache.CacheError as e: raise ActionError(e) try: command_list = shlex.split(command_cache, posix=False) result = execute.execute_binary( command_list[0], command_list[1:], success_codes + reboot_codes, shell=shell) except (execute.Error, ValueError) as e: raise ActionError(e) except KeyboardInterrupt: raise ActionError('KeyboardInterrupt detected, exiting.') if result in reboot_codes: raise RestartEvent( 'Restart triggered by exit code: %d' % result, 5, retry_on_restart=restart_retry) elif result not in success_codes: raise ActionError('Command returned invalid exit code: %d' % result)
def _LaunchPs(self, op: str, args: List[str], ok_result: Optional[List[int]] = None) -> int: """Launch the powershell executable to run a script. Args: op: -Command or -File args: any additional commandline args as a list ok_result: a list of acceptable exit codes; default is 0 Returns: Process returncode if successfully exited. Raises: PowerShellError: failure to execute powershell command cleanly """ if op not in ['-Command', '-File']: raise PowerShellError('Unsupported PowerShell parameter: %s' % op) try: return execute.execute_binary(_Powershell(), ['-NoProfile', '-NoLogo', op] + args, ok_result, self.shell, self.log) except execute.Error as e: raise PowerShellError(str(e))
def LaunchGooGet(self, pkg: str, retries: int, sleep: int, build_info: 'buildinfo.BuildInfo', **kwargs): """Launch the GooGet executable with arguments. Args: pkg: package name retries: number of times to retry a failed GooGet installation sleep: number of seconds between retry attempts build_info: current build information - used to get active release branch **kwargs: optional parameters such as path to GooGet binary, -reinstall, and/or -sources Raises: Error: The GooGet command failed. """ if not kwargs['path']: kwargs['path'] = os.path.join(self._GooGet(), 'googet.exe') if not os.path.exists(kwargs['path']): raise Error('Cannot find path of GooGet binary [%s]' % kwargs['path']) if not pkg: raise Error('Missing package name for GooGet install.') # Pass --root as GOOGETROOT environmental variable may not exist root = '--root=' + self._GooGet() cmd = ['-noconfirm', root, 'install'] if kwargs['flags']: cmd.extend(self._AddFlags(kwargs['flags'], build_info.Branch())) # Add the package name to the end of the command, this must be done last. cmd.append(pkg) max_attempts = retries + 1 for i in range(1, max_attempts + 1): logging.info('Attempt %d of %d', i, max_attempts) try: execute.execute_binary(kwargs['path'], cmd) return except execute.Error as e: logging.warning(str(e)) logging.info('Retrying in %d seconds', sleep) time.sleep(sleep) raise Error('GooGet command failed after %d attempts' % retries)
def domain_join(self, max_retries: Optional[int] = 5): """Execute the Splice CLI with defined flags. Args: max_retries: The number of times to attempt to download a file if the first attempt fails. A negative number implies infinite. Raises: Error: Domain join failed. """ args = [ '-cert_issuer=client', f'-cert_container={self.cert_container}', f'-name={self._get_hostname()}', f'-server={self.splice_server}', '-really_join=true', f'-user_name={self._get_username()}' ] attempt = 0 sleep = 30 while True: attempt += 1 try: execute.execute_binary(self.splice_binary, args, shell=True) except execute.Error: if max_retries < 0 or attempt < max_retries: logging.warning( 'Domain join attempt %d of %d failed. Retrying in %d second(s).', attempt, max_retries, sleep) time.sleep(sleep) else: raise Error( f'Failed to join domain after {max_retries} attempt(s).' ) else: logging.info('Domain join succeeded after %d attempt(s).', attempt) break