Deploying Native C/C++ Binary as a standalone Microservice in PCF-DEV - c

I have a use case to deploy a compiled Native C executable as a Microservice on PCF:
The compiled executable is called like so:
"mycbinary inputfile outputfile"
and terminates after the operation. The Microservice is thus not an LRP.
It is possibly a Task in PCF palance, but it does not rely on the existence of other Microservices.
It must be a standalone Microservice but not a long-running one.
How can I achieve this use case with PCF please, i.e what possibilities do I have?
The Microservice terminates when the binary is done with its work until it is needed again.
To test the feasibility of what I could do, I tried pushing some compiled C code to PCF-DEV.
I am using cf push since that's my understanding of a standalone App on PCF
cf push HelloServiceAgain -c './helloworld' -b https://github.com/cloudfoundry/binary-buildpack.git -u process --no-route
The push crashed with the following message:
Waiting for app to start...
Start unsuccessful
TIP: use 'cf.exe logs HelloService --recent' for more information
In the log file there was this entry:
OUT Process has crashed with type: "web"
Then I pushed another command which expects parameters. This started without a problem, but the same message in the log file
cf push HelloServiceGCC -c 'gcc -o ./hellogcc ./hello1.c' -b https://github.com/cloudfoundry/binary-buildpack.git -u process --no-route
I have the following additional questions please:
1) Is the message "Process has crashed with type: "web" an ERROR? And why is the command called multiple times?
2) The second push which succeeded is supposed to create a compiled hellogcc executable which I expect to see in the same root directory. Where is the output file created and how can I access it from the local file system?
Sorry for asking so many questions but I am a newbie in the PCF business.

The Microservice is thus not an LRP. It is possibly a Task in PCF palance, but it does not rely on the existence of other Microservices. It must be a standalone Microservice but not a long-running one.
It's definitely a task. It's fine that it does not rely on other services. A task is just simple a process that runs for a finite amount of time and exits 0 for success or something else for error.
cf push HelloServiceAgain -c './helloworld' -b https://github.com/cloudfoundry/binary-buildpack.git -u process --no-route
I would recommend using this slight variation: cf push HelloServiceAgain -c 'sleep 5000' -b binary_buildpack -u process --no-route.
This will...
Assume that the compiled binary is in the current directory.
Uses the system provided binary buildpack which should be fine.
Sets the health check to be based on the process & sets no route.
Runs sleep, which is merely to pass the health check.
The purpose of this is so that your application will upload & stage. We set the command to sleep because we just need the app to stage and start (this is a workaround to make sure that staging occurs, you have to run once to trigger staging at least at the moment). Once the app starts, just run cf stop and stop the app. Since all you have is the task, you don't need the app to continue running. If you update your app, you do need to follow this process again though, as that will restage your changes.
At this point, you can cf run-task and execute your program. Ex: cf run-task app-name './helloworld'.
Hope that helps!

Related

How to respond to any command line prompts in C

I'm trying to automate the process of doing
git add .
git commit -m "some message"
git push origin master
In C.
I've already done a bash script with Expect
#!/bin/bash
HOME="/home/prxvvy"
filename="$HOME/Documents/github_creds.txt"
username=`awk 'NR==1' $filename`
password=`awk 'NR==3' $filename`
echo "Enter a message for commit:"
read message
expect <<EOS
spawn git add .
expect
spawn git commit -m "$message"
expect
spawn git push origin master
expect "Username for 'https://github.com':"
send "$username\r"
expect "Password for 'https://$username#github.com':"
send "$password\r"
expect eof
EOS
So how would I "send" the requested data when the "Username for 'https://github.com':" prompt comes up, with C?
PS: I don't want to use any git api or something as I did in the bash script
Answer #1: you can't. The problem here has nothing to do with Git per se. Programs that read passwords from humans make sure they're not talking to other programs, by making sure they're using the human /dev/tty interface. So your program can't push a password into another program.
Answer #2: you can, but you must re-implement expect. The expect program tricks other programs into thinking they are talking to a human. This is fairly complicated and involves opening a "pseudo tty" from the control side, initializing it properly on the dependent side, and doing any OS-level operations required to make it become the /dev/tty that other programs will get when they open it. Then, having done all this song and dance (some of which is available in some libraries via openpty or similar), you can then run a program. You then must implement the rest of expect to read data coming through the control side of the pty pair, interpret it to figure out what the program is doing, and feed it data.
(Note that if all you want to do is run git push without having to enter a password, Git can invoke authentication methods that do this. Git does not have its own built in authentication: it relies on credential helpers when using https and ssh's credentialing and authentication systems when using ssh. So if you're using https:// for your URL, you want to configure a credential helper to do the job, and if you're using ssh:// for your URL, you want to configure ssh. You said that's not what you're interested in, though.)

Sytemd service fails when rebooting system using C reboot API

I am making a C++ program that creates a sytemd service file dynamically. This service executes a script on reboot. This script is also dynamically created and it deletes certain files, disables and deletes the service and then deletes itself.
My service is something like this:
[Unit]
Description = Run script on Reboot
Before =
[Service]
Type=simple
ExecStart=/var/tmp/myscript
[Install]
WantedBy=multi-user.target
And my script is:
rm -rf files
systemctl disable myservice.service
rm -f /etc/systemd/system/myservice.service
rm -f /var/tmp/myscript
After creation of the script and service, the program reboots the system using reboot API, passing LINUX_REBOOT_CMD_RESTART as parameter. However, my service fails after reboot and the files don't get deleted. I have even added the sync API before the reboot.
I have tested that service on its own, manually creating it and then manually rebooting the system, in that case, it works as intended. I even tried replacing the reboot API with
system("init 6")
And that too gives expected results. So, why is the reboot api in particular giving problem? what does that API do extra that can affect the service? I also have observed that there is some delay between the API call and the reboot starting, while calling system("init 6") has very less delay, almost starts reboot instantly.
What does the reboot do that could interfere with the service, and would passing some other parameter make behave same way as init 6?
Also, I am executing the program in sudo mode, hence the init command doesn't have extra sudo
Edit: I also tested out other reboot commands using the system C api. I tried system("reboot") and system("systemctl reboot") and both of them are working, the service runs fine on using them. So, the issue is only caused on using the reboot C Api. So, are there some differences in the api and that command? does the API do something extra that could interfere with the service?

macOS: Keep XPC Service (bundled) running after user quits main app

The bundled XPC Service in my macOS application need to do some post processing work with files dumped by the parent app, which most probably can't be completed within the usage time of the application. So, Is there a way to make the XPC service keep running even after the user quits the main app?
You could install it as launch daemon (running in root context as long as computer is switched on) or as launch agent (running in user context as long as user is logged in).
It sounds like you should be using the WatchPaths or QueueDirectories feature of launchd.
WatchPaths starts the job whenever any of the paths being watched have changed
or
QueueDirectories starts your job whenever the given directories are non-empty, and it keeps your job running as long as those directories are not empty
Both of these are covered by Apple's launchd documentation.

Spring Boot and Cloud deployment

I'm currently developping a REST API with Spring boot. I want it to deploy on google cloud (compute engine).
I created a virtual linux machine, installed java 8 and put my spring boot application inside it.
It works fine but :
my application is a jar file (embedded Tomcat). I launched it with this :
java -jar myApp.jar
And it works fine.
But when I close the shell on google cloud, my application is no longer available.
I would like my app to be always available, without having to launch it every time I quit the shell. Is it possible ?
image of cloud shell
I thing this is the same problem as this Unix Thread.
Fast answer is that your process is linked to the terminal. When you close it, the process is killed. If I quote this answer :
What nohup does, on the other hand, is to effectively separate the
process from the terminal:
It closes standard input (the program will not be able to read any >input, even if it is run in the foreground. it is not halted, but will
receive an error code or EOF).
It redirects standard output and standard error to the file nohup.out, so the program won't fail for writing to standard output if
the terminal fails, so whatever the process writes is not lost.
It prevents the process from receiving a SIGHUP (thus the name).
So, try
nohup java -jar myApp.jar &
If you use a virtual machine(google compute engine), you could use a script (bat in windows or sh in linux) to execute the java -jar command, but you can use too container engine and create a docker container with your app. configure a dockerfile and deploy. The container environment run your app automatically

How can I restart a service or reboot triggered by a Lighttpd CGI command?

I have created an application to run on an Olinuxino Maxi board which is presently running an Arch Linux ARM distribution. My somewhat simple application can be considered to be in two parts:
A program that performs communication between RS232 and TCP/IP, and initiates / accepts VOIP calls via the Linphone library. How this program behaves is configured through a .conf file. This program starts up on boot. I achieved the start up boot by creating a .service file for it and then enabling it using systemctl / systemd.
A simple web page that is accessed via Lighttpd. The CGI page is written in C. This page provides means for a user to edit the .conf file through a simple form, and therefore configure the operation of the main program.
All of the above now works. The specific problem I have relates to how I can cause my service program to restart (so that it configures itself again from the .conf file) when the user submits new settings via the web page. I'm stuck on this areas because, while I'm a fairly experienced C programmer, doing development on Linux and general Linux administration is fairly new ground to me.
In case it's relevant, I'll discuss a bit about how I've set this up, including how I've set up users and so forth:
I've set up a new user of the name of the application. Call it user application-name.
The RS232/TCP/IP/VOIP program resides in the folder /home/application-name/. The .conf file also resides in here.
systemd starts the program on boot. I understand that the program is being run as root.
The web / CGI code is located in /home/application-name/web/. I've set up an alias in the Lighttpd configuration is that /cgi-bin/ points to here, and that works.
The Lighttpd server, which I understand is run as user 'http', happily accesses the web page and, on submitting of POST data, edits the ../.conf file accordingly. To allow the web server to edit the .conf file I did have to chmod that file to allow write access to others, but I am guessing that a better way to do this would be to put users application-name and http into a new user group (though I'd appreciate advice on this also).
After processing of the POST data, my C CGI program also uses system() to call a bash script, restart_application.sh.
Inside restart_application.sh, I'm making a call to systemctl to restart my main program. But it doesn't work, and I gather it doesn't work because no user except root can invoke systemctl.
So the main question is:
How should I make my program restart?
And also:
If I'm doing any absolute horrors here in terms of my setup and Linux system administration, please by all means shout angrily.
Edit 1: Unless anyone has a better approach, I'm thinking of trying the idea suggested here which is to basically 'sudo' within the bash file.

Resources