Call shell script from within Google Cloud function
Question:
I am trying to invoke a simple shell script in a Google Cloud Function using Python.
However, for some reason the script cannot be found even though I found out that it is in the same directory on the environment .
The script of my main.py looks as it follows:
import subprocess
import os
def reload_plm(request):
request_json = request.get_json()
if request.args and 'message' in request.args:
return request.args.get('message')
elif request_json and 'message' in request_json:
return request_json['message']
else:
files = [f for f in os.listdir(os.getcwd()) if os.path.isfile(f)]
print(os.getcwd()) # output: /workspace
print(files) # output: ['gettoken.sh', 'k.key', 'main.py', 'requirements.txt']
load_token()
return f'Hello World!'
def load_token():
output = subprocess.call(["/workspace/gettoken.sh","k.key","argument1", "argument2"])
print(output)
As you can see I tried even using the absolute path of the script after the relative path did not work, but it is the same result which is:
FileNotFoundError: [Errno 2] No such file or directory: '/workspace/gettoken.sh'
or
FileNotFoundError: [Errno 2] No such file or directory: './gettoken.sh'
I tested the script locally and it did work. What am I doing wrong here?
Edit: As pointed out by Kolban one should not assume the existence of a certain OS environment. However if you find yourself on Linux this works:
Solution: I found the reason for this. It is because I used in my script #!/bin/sh
instead of bash. Apparently this shebang causes that only PATH
is evaluated but not the current directory. I solved this by modifying the command to . ./gettoken.sh
Answers:
The thinking is that maybe we want to avoid invoking shell scripts from within a Cloud Functions environment. The notion of Cloud Functions is that you are presented with an environment in which your programming language function can be executed. Executing a shell script from within makes assumptions including "Running in Linux/Unix", "Ability to fork an additional process", "Permissions to run script", "There is a shell binary to even be run". I’d suggest that if you want to own the environment, look to Cloud Run.
I tried using the same . ./sleep.sh and still get no file found
File struct:
main.py
sleep.sh
"/opt/python3.10/lib/python3.10/subprocess.py", line 969, in init
self._execute_child(args, executable, preexec_fn, close_fds, File
"/opt/python3.10 /lib/python3.10/subprocess.py", line 1845, in
_execute_child raise child_exception_type(errno_num, err_msg, err_filename) FileNotFoundError: [Errno 2] No such file or directory:
‘. ./sleep.sh’
main.py is same as your’s as i’m testing for sample now using your code:
tried "../sleep.sh" ".sleep.sh" "/workspace/.sleep.sh"
import subprocess
import os
def reload_plm(request):
request_json = request.get_json()
if request.args and 'message' in request.args:
return request.args.get('message')
elif request_json and 'message' in request_json:
return request_json['message']
else:
files = [f for f in os.listdir(os.getcwd()) if os.path.isfile(f)]
print(os.getcwd()) # output: /workspace
print(files) # output: ['sleep.sh','main.py','requirements.txt']
load_token()
return f'Hello World!'
def load_token():
output = subprocess.call([". ./sleep.sh"])
print(output)
I am trying to invoke a simple shell script in a Google Cloud Function using Python.
However, for some reason the script cannot be found even though I found out that it is in the same directory on the environment .
The script of my main.py looks as it follows:
import subprocess
import os
def reload_plm(request):
request_json = request.get_json()
if request.args and 'message' in request.args:
return request.args.get('message')
elif request_json and 'message' in request_json:
return request_json['message']
else:
files = [f for f in os.listdir(os.getcwd()) if os.path.isfile(f)]
print(os.getcwd()) # output: /workspace
print(files) # output: ['gettoken.sh', 'k.key', 'main.py', 'requirements.txt']
load_token()
return f'Hello World!'
def load_token():
output = subprocess.call(["/workspace/gettoken.sh","k.key","argument1", "argument2"])
print(output)
As you can see I tried even using the absolute path of the script after the relative path did not work, but it is the same result which is:
FileNotFoundError: [Errno 2] No such file or directory: '/workspace/gettoken.sh'
or
FileNotFoundError: [Errno 2] No such file or directory: './gettoken.sh'
I tested the script locally and it did work. What am I doing wrong here?
Edit: As pointed out by Kolban one should not assume the existence of a certain OS environment. However if you find yourself on Linux this works:
Solution: I found the reason for this. It is because I used in my script #!/bin/sh
instead of bash. Apparently this shebang causes that only PATH
is evaluated but not the current directory. I solved this by modifying the command to . ./gettoken.sh
The thinking is that maybe we want to avoid invoking shell scripts from within a Cloud Functions environment. The notion of Cloud Functions is that you are presented with an environment in which your programming language function can be executed. Executing a shell script from within makes assumptions including "Running in Linux/Unix", "Ability to fork an additional process", "Permissions to run script", "There is a shell binary to even be run". I’d suggest that if you want to own the environment, look to Cloud Run.
I tried using the same . ./sleep.sh and still get no file found
File struct:
main.py
sleep.sh
"/opt/python3.10/lib/python3.10/subprocess.py", line 969, in init
self._execute_child(args, executable, preexec_fn, close_fds, File
"/opt/python3.10 /lib/python3.10/subprocess.py", line 1845, in
_execute_child raise child_exception_type(errno_num, err_msg, err_filename) FileNotFoundError: [Errno 2] No such file or directory:
‘. ./sleep.sh’
main.py is same as your’s as i’m testing for sample now using your code:
tried "../sleep.sh" ".sleep.sh" "/workspace/.sleep.sh"
import subprocess
import os
def reload_plm(request):
request_json = request.get_json()
if request.args and 'message' in request.args:
return request.args.get('message')
elif request_json and 'message' in request_json:
return request_json['message']
else:
files = [f for f in os.listdir(os.getcwd()) if os.path.isfile(f)]
print(os.getcwd()) # output: /workspace
print(files) # output: ['sleep.sh','main.py','requirements.txt']
load_token()
return f'Hello World!'
def load_token():
output = subprocess.call([". ./sleep.sh"])
print(output)