.NET Core execute OS Command in Container problem - docker

i want to execute OS Command both windows and docker container (linux). When i control on windows every command which i entered work well because i can see output. When i build Dockerfile and run my app with container, send a few command i didn't take output what i expected.
My function is bellow.
public string RunCommand(string arguments)
{
var argsPrepend = "-c ";
var shellName = "/bin/sh";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
shellName = #"C:\Windows\System32\cmd.exe";
argsPrepend = "/c ";
}
try
{
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = shellName,
Arguments = argsPrepend + arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output;
}
catch (Exception ex)
{
return ex.ToString();
}
}
When i send pwd and ls command it works well.
swagger-pwd
swagger-ls
When i want to execute "ls -la /" or "cat /etc/passwd" i didn't get right output.
swagger-ls-la
swagger-cat-etc-passwd
How can i execute OS Command over Docker Container ?
What's the problem which i make or i face ?

1 - If you can access the directories you are running your file in and not other root directories, then there is the problem of not being able to read the file. You may need to check if the user you are running the file from has access.
2 - You may need to take a look at the "SecurityContext" configurations. I don't know about container structures. Maybe it's hardening in itself as a precaution. You may need to give permission yourself.
Link : https://techcommunity.microsoft.com/t5/azure-developer-community-blog/hardening-an-asp-net-container-running-on-kubernetes/ba-p/2542224
Best Regards.

Thanks for your helping. After gave my all 2 days's time :) i solved at the end. After i changed function likes bellow, everything works well.
public string RunCommand(string arguments)
{
var shellName = "/bin/bash";
var argsPrepend = "-c ";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
shellName = #"C:\Windows\System32\cmd.exe";
argsPrepend = "/c ";
}
try
{
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = shellName,
Arguments = argsPrepend + "\"" + arguments + "\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output;
}
catch (Exception ex)
{
return ex.ToString();
}
}

Related

Saxon CS: transform.doTransform cannot find out file from first transformation on windows machine but can on mac

I am creating an azure function application to validate xml files using a zip folder of schematron files.
I have run into a compatibility issue with how the URI's for the files are being created between mac and windows.
The files are downloaded from a zip on azure blob storage and then extracted to the functions local storage.
When the a colleague runs the transform method of the saxon cs api on a windows machine the method is able to run the first transformation and produce the stage 1.out file, however on the second transformation the transform method throws an exception stating that it cannot find the file even though it is present on the temp directory.
On mac the URI is /var/folders/6_/3x594vpn6z1fjclc0vx4v89m0000gn/T and on windows it is trying to find it at file:///C:/Users/44741/AppData/Local/Temp/ but the library is unable to find the file on the windows machine even if it is moved out of temp storage.
Unable to retrieve URI file:///C:/Users/44741/Desktop/files/stage1.out
The file is present at this location but for some reason the library cannot pick it up on the windows machine but it works fine on my mac. I am using Path.Combine to build the URI.
Has anyone else ran into this issue before?
The code being used for the transformations is below.
{
try
{
var transform = new Transform();
transform.doTransform(GetTransformArguments(arguments[Constants.InStage1File],
arguments[Constants.SourceDir] + "/" + schematronFile, arguments[Constants.Stage1Out]));
transform.doTransform(GetTransformArguments(arguments[Constants.InStage2File], arguments[Constants.Stage1Out],
arguments[Constants.Stage2Out]));
transform.doTransform(GetFinalTransformArguments(arguments[Constants.InStage3File], arguments[Constants.Stage2Out],
arguments[Constants.Stage3Out]));
Log.Information("Stage 3 out file written to : " + arguments[Constants.Stage3Out]);;
return true;
}
catch (FileNotFoundException ex)
{
Log.Warning("Cannot find files" + ex);
return false;
}
}
private static string[] GetTransformArguments(string xslFile, string inputFile, string outputFile)
{
return new[]
{
"-xsl:" + xslFile,
"-s:" + inputFile,
"-o:" + outputFile
};
}
private static string[] GetFinalTransformArguments(string xslFile, string inputFile, string outputFile)
{
return new[]
{
"-xsl:" + xslFile,
"-s:" + inputFile,
"-o:" + outputFile,
"allow-foreign=true",
"generate-fired-rule=true"
};
}```
So assuming the intermediary results are not needed as files but you just want the result (I assume that is the Schematron schema compiled to XSLT) you could try to run XSLT 3.0 using the API of SaxonCS (using Saxon.Api) by compiling and chaining your three stylesheets with e.g.
using Saxon.Api;
string isoSchematronDir = #"C:\SomePath\SomeDir\iso-schematron-xslt2";
string[] isoSchematronXslts = { "iso_dsdl_include.xsl", "iso_abstract_expand.xsl", "iso_svrl_for_xslt2.xsl" };
Processor processor = new(true);
var xsltCompiler = processor.NewXsltCompiler();
var baseUri = new Uri(Path.Combine(isoSchematronDir, isoSchematronXslts[2]));
xsltCompiler.BaseUri = baseUri;
var isoSchematronStages = isoSchematronXslts.Select(xslt => xsltCompiler.Compile(new Uri(baseUri, xslt)).Load30()).ToList();
isoSchematronStages[2].SetStylesheetParameters(new Dictionary<QName, XdmValue>() { { new QName("allow-foreign"), new XdmAtomicValue(true) } });
using (var schematronIs = File.OpenRead("price.sch"))
{
using (var compiledOs = File.OpenWrite("price.sch.xsl"))
{
isoSchematronStages[0].ApplyTemplates(
schematronIs,
isoSchematronStages[1].AsDocumentDestination(
isoSchematronStages[2].AsDocumentDestination(processor.NewSerializer(compiledOs)
)
);
}
}
If you only need the compiled Schematron to apply it further to validate an XML instance document against that Schematron you could even store the Schematron as an XdmDestination whose XdmNode you feed to XsltCompiler e.g.
using Saxon.Api;
string isoSchematronDir = #"C:\SomePath\SomeDir\iso-schematron-xslt2";
string[] isoSchematronXslts = { "iso_dsdl_include.xsl", "iso_abstract_expand.xsl", "iso_svrl_for_xslt2.xsl" };
Processor processor = new(true);
var xsltCompiler = processor.NewXsltCompiler();
var baseUri = new Uri(Path.Combine(isoSchematronDir, isoSchematronXslts[2]));
xsltCompiler.BaseUri = baseUri;
var isoSchematronStages = isoSchematronXslts.Select(xslt => xsltCompiler.Compile(new Uri(baseUri, xslt)).Load30()).ToList();
isoSchematronStages[2].SetStylesheetParameters(new Dictionary<QName, XdmValue>() { { new QName("allow-foreign"), new XdmAtomicValue(true) } });
var compiledSchematronXslt = new XdmDestination();
using (var schematronIs = File.OpenRead("price.sch"))
{
isoSchematronStages[0].ApplyTemplates(
schematronIs,
isoSchematronStages[1].AsDocumentDestination(
isoSchematronStages[2].AsDocumentDestination(compiledSchematronXslt)
)
);
}
var schematronValidator = xsltCompiler.Compile(compiledSchematronXslt.XdmNode).Load30();
using (var sampleIs = File.OpenRead("books.xml"))
{
schematronValidator.ApplyTemplates(sampleIs, processor.NewSerializer(Console.Out));
}
The last example writes the XSLT/Schematron validation SVRL output to the console but could of course also write it to a file.

Why does this script cause problems only on Jenkins?

I had to add a job in a multibranch pipeline.
The goal was to automatically install a plugin in jira.
The code runs perfectly fine because I tested it in a Unit Test.
But when I put it as a scripted pipeline on Jenkins, it does not do what it should do.
The goal is to install the plugin on jira, but when I run it on Jenkins it will not be installed.
Also I do not get any json Response, which I get in my JUnit Test.
I really do not know what is different on Jenkins. I already found it weird that I have to approve every single method in my script. Did someone have a similar issue on jenkins before.
I really appreciate your help.
#Test
public void test_install_plugin() throws IOException {
String jsonBody = "{\"pluginUri\": \"http://myServer/job/element/job/mybranch\", \"pluginName\": \"myPlugin\"}";
String token = "-6485649001990379871";
String jiraPath="myServer/rest/plugins/1.0/";
String query = "token="+token;
String url = jiraPath+"?"+query;
URL jiraURL = new URL(url);
HttpURLConnection jiraURLConnection = (HttpURLConnection)jiraURL.openConnection();
jiraURLConnection.setDoOutput(true);
jiraURLConnection.setDoInput(true);
jiraURLConnection.setRequestProperty ("Content-Length",String.valueOf(jsonBody.length()));
jiraURLConnection.setRequestProperty ("Accept", "application/json");
jiraURLConnection.setRequestProperty ("Content-Type", "application/vnd.atl.plugins.install.uri+json");
jiraURLConnection.setRequestProperty ("Authorization", "Basic YWRXXXXXXtaW4=");
jiraURLConnection.setRequestMethod("POST");
OutputStream os = null;
try {
os = jiraURLConnection.getOutputStream();
byte[] input = jsonBody.getBytes("utf-8");
os.write(input, 0, input.length);
os.flush();
}
catch(IOException ex)
{
System.out.println("Exception: " + ex.getMessage());
}
finally
{
os.close();
System.out.println("responseCode of install request: " + jiraURLConnection.getResponseCode());
}
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(jiraURLConnection.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println("Response: " + response.toString());
}
catch(IOException ex)
{
System.out.println("Exception: " + ex.getMessage());
}
finally
{
br.close();
jiraURLConnection.disconnect();
}
}

How to pipe to a process using vala/glib

I'm trying to pipe output from echo into a command using GLib's spawn_command_line_sync method. The problem I've run into is echo is interpreting the entire command as the argument.
To better explain, I run this in my code:
string command = "echo \"" + some_var + "\" | command";
Process.spawn_command_line_sync (command.escape (),
out r, out e, out s);
I would expect the variable to be echoed to the pipe and the command run with the data piped, however when I check on the result it's just echoing everything after echo like this:
"some_var's value" | command
I think I could just use the Posix class to run the command but I like having the result, error and status values to listen to that the spawn_command_line_sync method provides.
The problem is that you are providing shell syntax to what is essentially the kernel’s exec() syscall. The shell pipe operator redirects the stdout of one process to the stdin of the next. To implement that using Vala, you need to get the file descriptor for the stdin of the command process which you’re running, and write some_var to it manually.
You are combining two subprocesses into one. Instead echo and command should be treated separately and have a pipe set up between them. For some reason many examples on Stack Overflow and other sites use the Process.spawn_* functions, but using GSubprocess is an easier syntax.
This example pipes the output of find . to sort and then prints the output to the console. The example is a bit longer because it is a fully working example and makes use of a GMainContext for asynchronous calls. GMainContext is used by GMainLoop, GApplication and GtkApplication:
void main () {
var mainloop = new MainLoop ();
SourceFunc quit = ()=> {
mainloop.quit ();
return Source.REMOVE;
};
read_piped_commands.begin ("find .", "sort", quit);
mainloop.run ();
}
async void read_piped_commands (string first_command, string second_command, SourceFunc quit) {
var output = splice_subprocesses (first_command, second_command);
try {
string? line = null;
do {
line = yield output.read_line_async ();
print (#"$(line ?? "")\n");
}
while (line != null);
} catch (Error error) {
print (#"Error: $(error.message)\n");
}
quit ();
}
DataInputStream splice_subprocesses (string first_command, string second_command) {
InputStream end_pipe = null;
try {
var first = new Subprocess.newv (first_command.split (" "), STDOUT_PIPE);
var second = new Subprocess.newv (second_command.split (" "), STDIN_PIPE | STDOUT_PIPE);
second.get_stdin_pipe ().splice (first.get_stdout_pipe (), CLOSE_TARGET);
end_pipe = second.get_stdout_pipe ();
} catch (Error error) {
print (#"Error: $(error.message)\n");
}
return new DataInputStream (end_pipe);
}
It is the splice_subprocesses function that answers your question. It takes the STDOUT from the first command as an InputStream and splices it with the OutputStream (STDIN) for the second command.
The read_piped_commands function takes the output from the end of the pipe. This is an InputStream that has been wrapped in a DataInputStream to give access to the read_line_async convenience method.
Here's the full, working implementation:
try {
string[] command = {"command", "-options", "-etc"};
string[] env = Environ.get ();
Pid child_pid;
string some_string = "This is what gets piped to stdin"
int stdin;
int stdout;
int stderr;
Process.spawn_async_with_pipes ("/",
command,
env,
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
null,
out child_pid,
out stdin,
out stdout,
out stderr);
FileStream input = FileStream.fdopen (stdin, "w");
input.write (some_string.data);
/* Make sure we close the process using it's pid */
ChildWatch.add (child_pid, (pid, status) => {
Process.close_pid (pid);
});
} catch (SpawnError e) {
/* Do something w the Error */
}
I guess playing with the FileStream is what really made it hard to figure this out. Turned out to be pretty straightforward.
Based on previous answers probably an interesting case is to use program arguments to have a general app to pipe any input on it:
pipe.vala:
void main (string[] args) {
try {
string command = args[1];
var subproc = new Subprocess(STDIN_PIPE | STDOUT_PIPE, command);
var data = args[2].data;
var input = new MemoryInputStream.from_data(data, GLib.free);
subproc.get_stdin_pipe ().splice (input, CLOSE_TARGET);
var end_pipe = subproc.get_stdout_pipe ();
var output = new DataInputStream (end_pipe);
string? line = null;
do {
line = output.read_line();
print (#"$(line ?? "")\n");
} while (line != null);
} catch (Error error) {
print (#"Error: $(error.message)\n");
}
}
build:
$ valac --pkg gio-2.0 pipe.vala
and run:
$ ./pipe sort "cc
ab
aa
b
"
Output:
aa
ab
b
cc

Use OS.File to test if path is locked?

With OS.File I am able to open a file with lock on it:
let options = {
winShare: 0 // Exclusive lock on Windows
};
if (OS.Constants.libc.O_EXLOCK) {
// Exclusive lock on *nix
options.unixFlags = OS.Constants.libc.O_EXLOCK;
}
let file = yield OS.File.open(..., options);
Is it possible to test if the path is locked though. I'm looking for alternative to nsiToolkitProfile.lockProfile
This is copy paste to scratchpad code. The top block uses nsitoolkitprofile to test if locked. And it works fine. The second part uses OS.File.open and it always throws error.
Cu.import('resource://gre/modules/osfile.jsm');
Cu.import('resource://gre/modules/FileUtils.jsm');
var tps = Cc['#mozilla.org/toolkit/profile-service;1'].createInstance(Ci.nsIToolkitProfileService); //toolkitProfileService
var folderOfProfile = 'k46wtieb.clean'; //folder names of relative profiles found here: %APPDATA%\Mozilla\Firefox\Profiles
var rootPathDefault = FileUtils.getFile('DefProfRt', []).path;
var localPathDefault = FileUtils.getFile('DefProfLRt', []).path;
var aDirect = new FileUtils.File(OS.Path.join(rootPathDefault, folderOfProfile));
var aTemp = new FileUtils.File(OS.Path.join(localPathDefault, folderOfProfile));
try {
var locker = tps.lockProfilePath(aDirect, aTemp)
Services.ww.activeWindow.alert('NOT open');
locker.unlock();
} catch (ex) {
if (ex.result == Cr.NS_ERROR_FILE_ACCESS_DENIED) {
Services.ww.activeWindow.alert('its in use');
} else {
throw ex;
}
}
var promise = OS.File.open(aDirect.path)
promise.then(
function(aVal) {
Services.ww.activeWindow.alert('promise success, aVal = ' + aVal);
aVal.close();
},
function(aReason) {
Services.ww.activeWindow.alert('promise rejected, aReason = ' + uneval(aReason));
}
)
The promise is always rejected with aReason.becauseAccessDenied every time :(
Just try to open it... If you cannot because of permissions, then the file is probably locked in another location.

Creating a process in ASP.NET MVC controller

I have a requirement to run an application through my MVC controller. To get the installation path I used following link (I used answer provided by Fredrik Mörk). It worked and I could able to run the exe through a process. The problem occurred when I deployed this solution on IIS where it did not create the process as it was creating in local dev environment. Can anybody tell me how to create a windows process through a solution which is hosted on IIS ?
private string GetPathForExe(string fileName)
{
private const string keyBase = #"SOFTWARE\Wow6432Node\MyApplication";
RegistryKey localMachine = Registry.LocalMachine;
RegistryKey fileKey = localMachine.OpenSubKey(string.Format(#"{0}\{1}", keyBase, fileName));
object result = null;
if (fileKey != null)
{
result = fileKey.GetValue("InstallPath");
}
fileKey.Close();
return (string)result;
}
public void StartMyApplication()
{
Process[] pname = Process.GetProcessesByName("MyApplication");
if (pname.Length == 0)
{
string appDirectory = GetPathForExe("MyApplication");
Directory.SetCurrentDirectory(appDirectory);
ProcessStartInfo procStartInfo = new ProcessStartInfo("MyApplication.exe");
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
}
}

Resources