Cannot hit grpc server after successfully deploying to cloud run - python

Similar situation to what was asked here, however the solution described there do not work in my case. I want to run a grpc server on google cloud run, and be able to call it. I have a basic python grpc server that works fine and is able to be called by my client when running the gcr.io image on localhost with docker run. However, after successfully deploying to google cloud run, and with the server listening on port 8080 (I logged it), I am no longer able to reach the server with my client code.
I receive the following:
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
status = StatusCode.UNAVAILABLE
details = "DNS resolution failed"
debug_error_string = "{"created":"#1591245267.073965000","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":3981,"referenced_errors":[{"created":"#1591245267.073946000","description":"Resolver transient failure","file":"src/core/ext/filters/client_channel/resolving_lb_policy.cc","file_line":214,"referenced_errors":[{"created":"#1591245267.073945000","description":"DNS resolution failed","file":"src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc","file_line":357,"grpc_status":14,"referenced_errors":[{"created":"#1591245267.073882000","description":"C-ares status is not ARES_SUCCESS: Domain name not found","file":"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc","file_line":244,"referenced_errors":[{"created":"#1591245267.059636000","description":"C-ares status is not ARES_SUCCESS: Domain name not found","file":"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc","file_line":244}]}]}]}]}"
>
my server code is as follows:
def serve():
# expected port from google cloud run is 8080
port = os.getenv('PORT')
if not port:
port = server_port
server.add_insecure_port('[::]:{port}'.format(port=port))
server.start()
logger.info('listening on port {port}'.format(port=port))
server.wait_for_termination()
my client code, I have tried both
channel = grpc.insecure_channel('<the .run.app url on my cloud run service>:8080')
stub = my_service_pb2_grpc.MyServiceStub(channel)
request = my_service_pb2.MyEndpointRequest(
test='hello'
)
response = stub.MyEndpoint(request)
print(response)
and
with grpc.secure_channel('<the .run.app url on my cloud run service>:8080', grpc.ssl_channel_credentials()) as channel:
stub = my_service_pb2_grpc.MyServiceStub(channel)
request = my_service_pb2.MyEndpointRequest(
test='hello'
)
response = stub.MyEndpoint(request)
print(response)
both of which do not work and gives me the same error that I wrote above.
Furthermore, when I ping <the .run.app url on my cloud run service> on the command line I get Name or service not known.
Any help would be greatly appreciated!

Managed to solve it, the solution was to remove the https:// prefix from the url shown on the cloud run service and use the 443 port instead of 8080
with grpc.secure_channel(
'<url without https:// prefix>:443',
grpc.ssl_channel_credentials(),
) as channel:
stub = my_service_pb2_grpc.MyServiceStub(channel)
request = my_service_pb2.MyEndpointRequest(
test='hello'
)
response = stub.MyEndpoint(request)
print(response)

Related

Mosquitto - unable to connect from remote computer

I am trying to test a Mosquitto MQTT server. My plan is to hopefully get it to ingest some notifications from our monitoring system in my work IT dept. Seems perfect for the task. I was able to install Mosquitto on a Ubuntu 20.04 server, and testing with the mosquitto_sub and mosquitto_pub clients worked right away (see attached screenshot). I also was able to Google around and set up some Python script using paho mqtt module for subscribe and publish. I set up the subscribe script as a service and it runs fine. I can receive published messages from both mosquitto_pub and the "publish" Python script...
Now where the issues come up is when I try publishing to the Mosquitto server from a remote computer within my office. For the life of me I cannot determine what the issue is. :(
I am able to telnet to the Mosquitto server on port 1883 so it does not seem to be a firewall issue on the Mosquitto server... Whenever I try to use the publish Python script from the remote computer, it executes but it does not work -- no messages are received at the subscriber running on the server. One odd thing is that the "on_connect" portion on the script does not work when the script is run on the remote computer; no "Connected to MQTT Broker!" message is printed when the script is run remotely. (it does work when it's run locally on the Mosquitto server).
I am attaching a screenshot of my /etc/mosquitto/conf.d/default.conf file. I have tried all sorts of combinations on the config and each time things work when run on the server itself but not remotely. I tried putting the IP address for the server on the config as "listener 1883 10.x.x.x". (Note for this post using "10.x.x.x" instead of my real IP address.) The last thing I tried was putting the adapter name, and still does not work. As you can see I have also defined authentication (usernames, passwords) for a pubuser and subuser. The account info does work with the mosquitto_sub and mosquitto_pub clients, and when used in Python scripts (when script are run on Mosquitto server) so I don't think it's an account info issue. All signs are pointing to either some misconfiguration I have in Mosquitto, or some firewall policy in my work location. Please help!
Please share any tips or possible fixes for me. I might be doing something wrong in my config; please do let me know if you see something amiss. I am a newbie with Mosquitto and MQTT but would love for it to work, kind of ruins the point if I cannot publish to the server form a remote computer though :)..
Below is example Python code I am using on the remote computer to publish (works run locally on the Mosquitto server). I redacted the IP address of the server with 10.x.x.x).
When I run the script from the remote computer I just get "Failed to send message to topic python/mqtt".
:
import random
import time
from paho.mqtt import client as mqtt_client
broker = '10.x.x.x'
port = 1883
topic = "python/mqtt"
# generate client ID with pub prefix randomly
#client_id = f'python-mqtt-{random.randint(0, 1000)}'
#Set the static client id
client_id = 'python-mqtt01'
username = 'pubuser'
password = 'something'
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
return client
def publish(client):
msg_count = 0
while True:
time.sleep(1)
msg = f"messages: {msg_count}"
result = client.publish(topic, msg)
# result: [0, 1]
status = result[0]
if status == 0:
print(f"Send `{msg}` to topic `{topic}`")
else:
print(f"Failed to send message to topic {topic}")
msg_count += 1
def run():
client = connect_mqtt()
client.loop_start()
publish(client)
if __name__ == '__main__':
run()
Thanks for reading! Hopefully someone out there has encountered the same issue and fixed it!
P.S. - forgot to mention I also disabled the firewall on the Ubuntu server until I get things working (ufw disable).
Example of my default.cfg (before) removing adapter and adding log_type all:
listener 1883
allow_anonymous false
bind_interface ens33

How to get the ip address of a request machine using python (On Sanic)

I am trying to get the IP address of the requesting computer on my server. I can successfully get the IP-address from request header if the request came from a web browser. The code example below. However, I cannot fetch the client IP, if I send the request via curl/postman. I checked the nginx log, and I found there is a log of my public IP when I sent a curl request. How can I achieve this?
PS: I am using the Sanic Framework.
client_ip = request.headers.get('x-real-ip')
In sanic's docs for Request Data:
ip (str) - IP address of the requester.
Therefore, just use
client_ip = request.ip

sending a python request to a different host on the same network

Currently I have something called a client, and a server.py that is running a flask server. I also have a different machine running a different flask server. (With the host being the ip address of the machine)
on one of the app routes, it will reroute the request to the different machine (Because of reasons) to process
Essentially, it looks something like this
server.py
#app.route('/endpointapi', methods = ['POST'])
def doStuff():
f = request.form['message']
correctURL = "http://somenumber.2.3:port/endpointapi"
r = requests.post(correctURL, data={'message', f})
return r
differentMachineOneSameNetwork.py
#app.route('/endpointapi', methods = ['POST'])
def doStuff():
//does things correctly
return updated message
The somenumber.2.3 is a valid ip address of the machine that is running differentMachineOneSameNetwork.py along with the port. Both machines are running a flask webserver, but the client can only send requests to the server.py. However, it is not connecting. Is there any reason why it might not be working?
EDIT
The ports are artifically chosen. 5555 for the server.py, and 8090 for the different machine. It works when we just test connections from the same machine to its own using curl commands, but it does not work when we try to curl from server machine to the other machine.
Whats working:
Curl from server to server flask
Curl from differentMachine to differentMachine flask
Curl from differentMachine to server flask
Not working:
Curl from server to differentMachine doesn't work. Connection just times out. Example command that was sent:
curl -X POST -F "message=some bojangle" http://correct.ip.address:8090/endpointapi
I get:
curl: (7) Failed to connect to correct.ip.address port 8090: Connection timed out
It just times out after trying to establish a connection, giving http response code of 500.

printing URL parameters of a HTTP request using Python + Nginx + uWSGI

I have used this link and successfully run a python script using uWSGI. Although i just followed the doc line by line.
I have a GPS device which is sending data to a remote server. Document of the same device say that it connect to server using TCP which therefore would be http as simple device like a GPS device would not be able to do https (i hope i am right here.) Now as i have configure my Nginx server to forward all incoming HTTP request to python script for processing via uWSGI.
What i want to do is to simply print the url or query string on the HTML page. As i don't have control on the device side (i can only configure device to send data on a IP + Port), i have no clue how data is coming. Below is my access log
[23/Jan/2016:01:50:32 +0530] "(009591810720BP05000009591810720160122A1254.6449N07738.5244E000.0202007129.7200000000L00000008)" 400 172 "-" "-" "-"
Now i have look at this link on how to get the url parameters values, but i don't have a clue that what is the parameter here.
I tried to modified my wsgi.py file as
import requests
r = requests.get("http://localhost.com/")
# or r = requests.get("http://localhost.com/?") as i am directly routing incoming http request to python script and incoming HTTP request might not have #any parameter, just data #
text1 = r.status_code
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["<h1 style='color:blue'>Hello There shailendra! %s </h1>" %(text1)]
but when i restarted nginx, i get internal server error. Can some one help me to understand wrong i am doing here (literally i have no clue about the parameters of the application function. Tried to read this link, but what i get from here is that environ argument take care of many CGI environment variables.)
Can some one please help me to figure out what wrong am i doing and guide me to even a doc or resource.
Thanks.
why are you using localhost ".com" ?
Since you are running the webserver on the same machine,
you should change the line to
r = requests.get("http://localhost/")
Also move below lines from wsgi.py and put them in testServerConnection.py
import requests
r = requests.get("http://localhost/")
# or r = requests.get("http://localhost.com/?") as i am directly routing incoming http request to python script and incoming HTTP request might not have #any parameter, just data #
text1 = r.status_code
Start NGINX
and you also might have to run (i am not sure uwsgi set up on nginx)
uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi
run testConnection.py to send a test request to localhost webserver and print the response
i got the answer for my question. Basically to process a TCP request, you need to open a socket and accept the TCP request on a specific port (as you specified on the hardware)
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
#data which is received
print self.data
if __name__ == "__main__":
#replace IP by your server IP
HOST, PORT = <IP of the server>, 8000
# Create the server, binding to localhost on port 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
After you get the data, you can do any thing with the data. As my data format was shared in the GPS datasheet, i was able to parse the string and get the Lat and long out of it.

Google API oauth httpd server conflicts with SABNzbd+ in Python

I'm writing a Python app that interacts with a Google API and requires user authentication via oauth2.
I'm currently setting up a local authentication server to receive an oauth2 authentication code back from Google's oauth server, basically doing the oauth dance like this.
It usually works pretty well, but I guess I'm not understanding exactly how it's interacting with my ports, because it will happily assign my local authentication server to run on port 8080 even if some other app (in the case of my testing, SABNzbd++) is using that port.
I thought assigning the port to a used port number would result in an error and a retry. What am I doing wrong (or, alternatively, what is SABNzbd++ doing that keeps the fact that it's listening on port 8080 hidden from my app?)
The relevant code is as follows.
import socket
import BaseHTTPServer
from oauth2client.tools import ClientRedirectServer, ClientRedirectHandler
port_number = 0
host_name = 'localhost'
for port_number in range(8080,10000):
try:
httpd = ClientRedirectServer((host_name, port_number),
ClientRedirectHandler)
except socket.error, e:
print "socket error: " + str(e)
pass
else:
print "The server is running on: port " + str(port_number)
print "and host_name " + host_name
break
To clarify, the following are my expected results
socket error: [port already in use] (or something like that)
The server is running on: port 8081
and host_name localhost
and then going to localhost:8080 resolves to SABnzbd+, and localhost:8081 resolves to my authentication server.
I'm getting, howver:
the server is running on: port 8080
and host_name localhost
but going to localhost:8080 resolves to SABNzbd+
Thanks in advance!

Categories

Resources