diff --git a/.travis.yml b/.travis.yml index 3829d8e..7c77844 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ install: - pip install -r external_requirements.txt --extra-index-url https://pypi.python.org/simple - pip install -r test_requirements.txt --extra-index-url https://pypi.python.org/simple - pip install "cloudshell-shell-core>=3.1.0,<3.2.0" --extra-index-url https://testpypi.python.org/simple - - pip install "cloudshell-automation-api>=8.2.0.0,<8.2.1.0" --extra-index-url https://testpypi.python.org/simple + - pip install "cloudshell-automation-api>=8.3.0.0,<8.3.1.0" --extra-index-url https://testpypi.python.org/simple script: - pushd package diff --git a/README.md b/README.md index 981be81..1a656d0 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,6 @@ # CustomScript-Shell + +## Links +* [Offline Package] (https://support.quali.com/hc/en-us/articles/231613247) diff --git a/drivers/customscript_shell/drivermetadata.xml b/drivers/customscript_shell/drivermetadata.xml index 78d8490..4f812f0 100644 --- a/drivers/customscript_shell/drivermetadata.xml +++ b/drivers/customscript_shell/drivermetadata.xml @@ -1,4 +1,4 @@ - + diff --git a/drivers/customscript_shell/requirements.txt b/drivers/customscript_shell/requirements.txt index b8dcea7..d618050 100644 --- a/drivers/customscript_shell/requirements.txt +++ b/drivers/customscript_shell/requirements.txt @@ -1,2 +1,2 @@ cloudshell-shell-core>=3.1.0,<3.2.0 -cloudshell-cm-customscript>=1.3.0,<1.4.0 +cloudshell-cm-customscript>=1.4.0,<1.5.0 diff --git a/drivers/version.txt b/drivers/version.txt index 589268e..e21e727 100644 --- a/drivers/version.txt +++ b/drivers/version.txt @@ -1 +1 @@ -1.3.0 \ No newline at end of file +1.4.0 \ No newline at end of file diff --git a/package/cloudshell/cm/customscript/domain/linux_script_executor.py b/package/cloudshell/cm/customscript/domain/linux_script_executor.py index d26ef52..c6311c2 100644 --- a/package/cloudshell/cm/customscript/domain/linux_script_executor.py +++ b/package/cloudshell/cm/customscript/domain/linux_script_executor.py @@ -47,8 +47,10 @@ def connect(self): key_stream = StringIO(self.target_host.access_key) key_obj = RSAKey.from_private_key(key_stream) self.session.connect(self.target_host.ip, username=self.target_host.username, pkey=key_obj) - else: + elif self.target_host.username: raise Exception('Both password and access key are empty.') + else: + raise Exception('Machine credentials are empty.') except NoValidConnectionsError as e: error_code = next(e.errors.itervalues(), type('e', (object,), {'errno': 0})).errno raise ExcutorConnectionError(error_code, e) diff --git a/package/cloudshell/cm/customscript/domain/script_downloader.py b/package/cloudshell/cm/customscript/domain/script_downloader.py index cd591fe..0f1a4e3 100644 --- a/package/cloudshell/cm/customscript/domain/script_downloader.py +++ b/package/cloudshell/cm/customscript/domain/script_downloader.py @@ -45,8 +45,17 @@ def download(self, url, auth): file_txt += ''.join(chunk) self.cancel_sampler.throw_if_canceled() + self._validate_response(response, file_txt) + return ScriptFile(name=file_name, text=file_txt) + def _validate_response(self, response, content): + if response.status_code < 200 or response.status_code > 300: + raise Exception('Failed to download script file: '+str(response.status_code)+' '+response.reason) + + if content.lstrip('\n\r').lower().startswith(''): + raise Exception('Failed to download script file: url points to an html file') + def _get_filename(self, response): file_name = None for header_value, pattern in self.filename_patterns.iteritems(): diff --git a/package/cloudshell/cm/customscript/domain/windows_script_executor.py b/package/cloudshell/cm/customscript/domain/windows_script_executor.py index 4fdc829..5e16abc 100644 --- a/package/cloudshell/cm/customscript/domain/windows_script_executor.py +++ b/package/cloudshell/cm/customscript/domain/windows_script_executor.py @@ -114,11 +114,11 @@ def copy_script(self, tmp_folder, script_file): for bulk in bulks: encoded_bulk = base64.b64encode(bulk.encode("utf-8")) code = """ -$path = Join-Path "%s" "%s" -$data = [System.Convert]::FromBase64String("%s") +$path = Join-Path "{0}" "{1}" +$data = [System.Convert]::FromBase64String("{2}") Add-Content -value $data -encoding byte -path $path -""" - result = self._run_cancelable(code, tmp_folder, script_file.name, encoded_bulk) +""".format(tmp_folder, script_file.name, encoded_bulk) + result = self._run_cancelable(code) if result.status_code != 0: raise Exception(ErrorMsg.COPY_SCRIPT % result.std_err) @@ -134,10 +134,10 @@ def run_script(self, tmp_folder, script_file, env_vars, output_writer, print_out for key, value in (env_vars or {}).iteritems(): code += '\n$env:%s = "%s"' % (key, str(value)) code += """ -$path = Join-Path "%s" "%s" +$path = Join-Path "{0}" "{1}" Invoke-Expression "& '$path'" -""" - result = self._run_cancelable(code, tmp_folder, script_file.name) +""".format(tmp_folder, script_file.name) + result = self._run_cancelable(code) if print_output: output_writer.write(result.std_out) output_writer.write(result.std_err) @@ -163,8 +163,10 @@ def delete_temp_folder(self, tmp_folder): # self.logger.debug('Stderr:' + result.std_err) # return result - def _run_cancelable(self, txt, *args): - ps_code = txt % args + def _run_cancelable(self, ps_code): + """ + :type ps_code: str + """ self.logger.debug('PowerShellScript:' + ps_code) bat_code = 'powershell -encodedcommand %s' % base64.b64encode(ps_code.encode('utf_16_le')).decode('ascii') diff --git a/package/requirements.txt b/package/requirements.txt index 1cde969..1b9e97e 100644 --- a/package/requirements.txt +++ b/package/requirements.txt @@ -1,4 +1,4 @@ -cloudshell-automation-api>=8.2.0.0,<8.2.1.0 +cloudshell-automation-api>=8.3.0.0,<8.3.1.0 cloudshell-shell-core>=3.1.0,<3.2.0 pywinrm>=0.2.2 paramiko>=2.1.1 diff --git a/package/tests/test_linux_script_executor.py b/package/tests/test_linux_script_executor.py index 4014a93..454f7ad 100644 --- a/package/tests/test_linux_script_executor.py +++ b/package/tests/test_linux_script_executor.py @@ -64,6 +64,12 @@ def test_no_password_nor_pen_file(self): executor.connect() self.assertEqual('Both password and access key are empty.', e.exception.inner_error.message) + def test_no_password_no_pen_file_no_username(self): + executor = LinuxScriptExecutor(self.logger, self.host, self.cancel_sampler) + with self.assertRaises(Exception) as e: + executor.connect() + self.assertEqual('Machine credentials are empty.', e.exception.inner_error.message) + def test_create_temp_folder_success(self): self._mock_session_answer(0,'tmp123','') result = self.executor.create_temp_folder() diff --git a/package/tests/test_windows_script_executor.py b/package/tests/test_windows_script_executor.py index 058846b..7ca0529 100644 --- a/package/tests/test_windows_script_executor.py +++ b/package/tests/test_windows_script_executor.py @@ -74,6 +74,12 @@ def test_copy_script_fail(self): # Run script + def test_get_expected_file_extensions(self): + executor = WindowsScriptExecutor(self.logger, self.host, self.cancel_sampler) + file_extensions = executor.get_expected_file_extensions() + self.assertTrue(len(file_extensions)==1) + self.assertTrue('.ps1' in file_extensions) + def test_run_script_success(self): executor = WindowsScriptExecutor(self.logger, self.host, self.cancel_sampler) output_writer = Mock() diff --git a/package/version.txt b/package/version.txt index 589268e..e21e727 100644 --- a/package/version.txt +++ b/package/version.txt @@ -1 +1 @@ -1.3.0 \ No newline at end of file +1.4.0 \ No newline at end of file diff --git a/version.txt b/version.txt index 589268e..e21e727 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.3.0 \ No newline at end of file +1.4.0 \ No newline at end of file