How to get a file from a server in a cluster in Vsphere using pyVmomi to remote(host) pc - python-3.x

I am able to execute a command inside the server but I want to get that output in my local pc. I don't want want to use ssh keys. I want to use just the host's username and password as well as vm's(server's) username and password. I couldn't find a direct method to get the shell output of server in my pc, but this method seems half done like generate and save the output in server and then get the file from server. I am finding it difficult to get file(sample.txt) from server to local host(pc).
[EDIT: I am able to do this using via via method(Store the output to server and then get it back into local pc, is there a direct method ?) ]
from pyVim import connect
from config import *
from pyVmomi import vim, vmodl
import ssl
service_instance = connect.SmartConnect(host="yyyyyyy", port=some_number,user="xxx" , pwd=pwd,sslContext=ssl._create_unverified_context())
content = service_instance.RetrieveContent()
vm = searcher.FindByIp(ip="zzzzzz", vmSearch=True)
creds = vim.vm.guest.NamePasswordAuthentication(username='root', password=vmpwd)
pm = service_instance.content.guestOperationsManager.processManager
#checks python version and stores in sample.txt in server
ps = vim.vm.guest.ProcessManager.ProgramSpec(programPath='/usr/bin/python', arguments='--version &> sample.txt')
res = pm.StartProgramInGuest(vm, creds, ps)
print(res) #Prints pid

This does the job but I would appreciate if someone knows how to directly get the output of shell command from server to my local pc. This code makes a file with the output of cmd inside the server and it gets copied into my local pc
from pyVim import connect
from config import *
from pyVmomi import vim, vmodl
import ssl
import os
import requests
service_instance = connect.SmartConnect(host="xxxx", port=aaa,user="yyy" , pwd=pwd,sslContext=ssl._create_unverified_context())
content = service_instance.RetrieveContent()
# # Find a VM
vm = searcher.FindByIp(ip="aaaa", vmSearch=True)
creds = vim.vm.guest.NamePasswordAuthentication(username='root', password=vmpwd)
pm = service_instance.content.guestOperationsManager.processManager
#executes and saves sample.txt into server
ps = vim.vm.guest.ProcessManager.ProgramSpec(programPath='/usr/bin/python', arguments='--version &> sample.txt')
res = pm.StartProgramInGuest(vm, creds, ps)
dest="/Users/username/Desktop/vcenter/sample.txt" #My local pc
src="/root/sample.txt" #Server's directory
fti = content.guestOperationsManager.fileManager.InitiateFileTransferFromGuest(vm, creds, src)
resp=requests.get(fti.url, verify=False)
#Writes into file
with open(dest, 'wb') as f:
f.write(resp.content)

Related

Python configparser remote file in Gitlab

I have requirement to refactor a K8s Python app so that it gets some configuration from a remote Giltab project because for various reasons we want to decouple applicaton settings from our pipeline/deployment environment.
In my functional testing, this works:
import configparser
config = configparser.ConfigParser()
config_file = "config.ini" # local file for testing
config.read(config_file)
['config.ini']
However, when I attempt to read the configuration from a remote file (our requirement), this DOES NOT work:
import requests
import os
token = os.environ.get('GITLAB_TOKEN')
headers = {'PRIVATE_TOKEN': token}
params = { 'ref' : 'master' }
response = requests.get('https:/path/to/corp/gitlab/file/raw', params=params,
headers=headers
config = configparser.ConfigParser()
configfile = response.content.decode('utf-8')
print(configfile) # this is good!
config.read(configfile) # this fails to load the contents into configparser
[]
I get an empty list. I can create a file and or print the contents of the configfile object from the requests.get call, and the ini data looks good. config.read() seems unable to load this as an object in memory and only seems to work by reading a file from disk. Seems like writing the contents of the requests.get to a local .ini file would defeat the whole purpose of using the remote configuration repo.
Is there a good way to read that configuration file from the remote and have configparser access it at container runtime?
I got this working with:
config.read_string(configfile)

How to run an XMLRPC server and an XMLRPC client on Mininet hosts through a python script?

I am trying to run an XMLRPC server and an XMLRPC client on Mininet hosts, using the script below.
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import OVSController
class MyTopo(Topo):
def __init__(self):
# Initialize topology
Topo.__init__(self)
# Add hosts
server1 = self.addHost('server1')
server2 = self.addHost('server2')
# Add switch
s1 = self.addSwitch('s1')
# Add links
self.addLink(server1, s1)
self.addLink(server2, s1)
if __name__ == '__main__':
net = Mininet(topo=MyTopo(), controller=OVSController)
net.start()
print(net.hosts[0].cmd('python3 xmlrpc_server.py'))
print(net.hosts[1].cmd('python3 xmlrpc_client.py'))
The file xmlrpc_server.py is:
from xmlrpc.server import SimpleXMLRPCServer
import threading
def is_even(n):
return n%2 == 0
server = SimpleXMLRPCServer(("0.0.0.0", 8000), logRequests=True, allow_none = True)
server.register_function(is_even, "is_even")
print("Listening on port 8000...")
server_thread = threading.Thread(target=server.serve_forever)
server_thread.start()
The file xmlrpc_client.py is:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://10.0.0.1:8000/")
print("3 is even: %s" % str(proxy.is_even(3)))
print("100 is even: %s" % str(proxy.is_even(100)))
The problem is that although I have used a thread, when I run the xmlrpc_server.py script on server1, the execution pauses at line server_thread.start() waiting for the script execution to be completed before moving on and thus never goes on to the next line, which means that the XMLRPC client script never runs. How do I overcome this problem?
P.S.: xmlrpc_server.py and xmlrpc_client.py can be executed through the server terminals (by using the commands xterm server1 and xterm server2 on Mininet CLI and then using the commands python3 xmlrpc_server.py and python3 xmlrpc_client.py on the xterm terminals that open), but I need to start the server and client through a python script so as to perform some further calculations after the communication between the two servers.
Replace print(net.hosts[0].cmd('python3 xmlrpc_server.py')) with print(net.hosts[0].sendCmd('python3 xmlrpc_server.py')). Connection is sometimes refused, but that issue can be resolved with exception handling on the client script.

Why does f.write() in a Python file on a server not work?

I have a Python app that works locally, but on the server something goes wrong. So I have to do some debugging in an SSH session. The server logs tell me that something goes wrong in utils/do_something.py. I have created utils/log (rights 777), where the debugging values are supposed to go.
do_something.py looks like this:
import os
parent_folder = os.path.dirname(__file__)
log_file = os.path.join(parent_folder, 'log')
def do_something(arg1, arg2):
print('XXX')
f = open(log_file, 'a')
f.write('XXX\n')
stuff = goes.wrong
Loading the page causes do_something to run (as confirmed by the error logs). Locally the expected XXX appears in the console and in the log file. But nothing happens on the server.
I created a second file utils/blah.py:
print('BLAH')
import os
parent_folder = os.path.dirname(__file__)
log_file = os.path.join(parent_folder, 'log')
f = open(log_file, 'a')
f.write('BLAH\n')
When I run it with python blah.py, the expected BLAH appears in the console and the logfile.
I don't care that much about the difference between local and production server.
But I would like to understand the difference between do_something.py and blah.py.
Is there a better way to debug in an SSH session?
I work in a virtualenv in a mod_wsgi 4.6.5/Python3.7 environment on a Webfaction server. Some details about it can be seen in this question on the Webfaction forum.
Edit 1: On the server print seems to be discouraged anyway.
(See Where do things go when I ‘print’ them from my Django app?)
But what matters to me is f.write(). I just added print for comparison.
Edit 2: It is the same when I use the logging module. It works when I run blah.py, but nothing happens when loading the page runs do_something.
Edit 3: I tried the same with a simpler app, and the result is the same.I added the logging in views.py:
from django.http import HttpResponse
import os
parent_folder = os.path.dirname(__file__)
log_file = os.path.join(parent_folder, 'log')
def home_view(request):
f = open(log_file, 'a')
f.write('XXX\n')
return HttpResponse("Hello from home view.")
Locally this writes XXX to the log file every time the page is loaded. But not on the server.There are no errors in the server log.
Using the logging module: I am not sure why that did not work, but now it does.
import os
import logging
parent_folder = os.path.dirname(__file__)
log_file = os.path.join(parent_folder, 'log')
logging.basicConfig(filename=log_file, level=logging.DEBUG)
logging.debug('This works.')
Possibly I have used it with filename='log' instead of filename=log_file.
Locally the former creates the log file in the root folder. But on the server it must already exist.
Writing rights: It seems worth mentioning that touch log gave me a file I could not wright to, and lacking sudo I could not use chmod. So I used the trick install -b -m 777 /dev/null log.
It appears that you never explicitly close the file after writing, so the output is probably buffered. Your server and your local machine may have different settings with respect to file buffering, which would explain the differences you're experiencing.
If you want to open, write, and close a file, python's context managers are the best way to do it:
def home_view(request):
with open(log_file, 'a') as f:
f.write('XXX\n')
return HttpResponse("Hello from home view.")
You might check the privileges on the utils folder, and on any parent folders. Many times an http server will be running as user 'nobody', which has practically zip privileges. So unless the utils folder itself also has 0777 privileges, that could create a problem. You also might want to put the f.write in a try ... except block so that you can catch the error specifically and create a more useful / informative message about the error. Best.

Controlling a minecraft server with python

I've searched a lot for this and have not yet found a definitive solution. The closest thing I've found is this:
import shutil
from os.path import join
import os
import time
import sys
minecraft_dir = ('server diectory')
world_dir = ('server world driectory')
def server_command(cmd):
os.system('screen -S -X stuff "{}\015"'.format(cmd))
on = "1"
while True:
command=input()
command=command.lower()
if on == "1":
if command==("start"):
os.chdir(minecraft_dir)
os.system('"C:\Program Files\Java\jre1.8.0_111\bin\java.exe" -Xms4G -Xmx4G -jar craftbukkit-1.10.2.jar nogui java')
print("Server started.")
on = "0"
else:
server_command(command)
When I launch this program and type 'start' the CMD flashes up and closes instantly. Instead I want the CMD to stay open with the minecraft sever running from it. I'm not sure why this happens or what the problem is, any help would be greatly appreciated.
p.s. I have edited this to my needs (such as removing a backup script that was unnecessary) but it didn't work before. The original link is: https://github.com/tschuy/minecraft-server-control
os.system will simply run the command then return to your python script with no way to further communicate with it.
On the other hand using subprocess.Popen gives you access to the process while it runs, including writing to it's .stdin which is how you send data to the server:
def server_command(cmd):
process.stdin.write(cmd+"\n") #just write the command to the input stream
process = None
executable = '"C:\Program Files\Java\jre1.8.0_111\bin\java.exe" -Xms4G -Xmx4G -jar craftbukkit-1.10.2.jar nogui java'
while True:
command=input()
command=command.lower()
if process is not None:
if command==("start"):
os.chdir(minecraft_dir)
process = subprocess.Popen(executable, stdin=subprocess.PIPE)
print("Server started.")
else:
server_command(command)
you can also pass stdout=subprocess.PIPE so you can also read it's output and stderr=subprocess.PIPE to read from it's error stream (if any)
As well instead of process.stdin.write(cmd+"\n") you could also use the file optional parameter of the print function, so this:
print(cmd, file=process.stdin)
Will write the data to process.stdin formatted in the same way that print normally does, like ending with newline for you unless passing end= to override it etc.
Both of the above answers do not work in the environment I tried them in.
I think the best way is to use RCON, not sending keys to a window.
RCON is the protocol used by games to run commands.
Many python libraries support Minecraft RCON, and the default server.properties file has an option for RCON.
We will use the python module: MCRON.
Install it. It works for windows, mac, linux.
Type:
pip install mcrcon
Lets configure your server to allow RCON.
In server.properties, find the line 'enable-rcon' and make it look like this:
enable-rcon=true
Restart and stop your server.
Find the line 'rcon.password' and set it to any password you will remember.
You can leave the port default at 25575.
Now, open your terminal and type:
mcron localhost
Or your server ip.
You will be prompted to enter the password you set.
Then you can run commands and will get the result.
But we are doing this with python, not the PYPI MCRON scripts - so do this.
from mcrcon import MCRcon as r
with r('localhost', 'insertyourpasswordhere') as mcr:
resp = mcr.command('/list')
print(resp) #there are 0/20 players online: - This will be different for you.

How to get VNC port number using libvirt?

I set autoport=yes in a domain's("virtual machine" in libvirt) config file so the VNC port is assigned automatically in the run time.
I need to get this port so I can connect to the vm from outside, but I can't find the proper API to do so. Better in python because I'm using the libvirt-python bindings.
I have not found any API for the VNC port, not sure if the newer version of libvirt has this interface?
However, you can use the command virsh vncdisplay $domainName to show the port. NOTE: you must modify /etc/libvirt/qemu.conf enable vnc_listen='0.0.0.0'.
There's no API to get the VNC port. You have to take and parse the XML file to find out that port. Of course if the guest is destroyed (powered off/offline) that port will be a value of -1.
char * virDomainGetXMLDesc (virDomainPtr domain, unsigned int flags)
<domain>
<devices>
<graphics type='vnc' port='5900' autoport='yes'/>
</devices>
</domain>
References
http://libvirt.org/html/libvirt-libvirt.html#virDomainGetXMLDesc
Here's how you do it in python, in case anyone needs this.
Save as vncport.py
from xml.etree import ElementTree as ET
import sys
import libvirt
conn = libvirt.open()
domain = conn.lookupByName(sys.argv[1])
#get the XML description of the VM
vmXml = domain.XMLDesc(0)
root = ET.fromstring(vmXml)
#get the VNC port
graphics = root.find('./devices/graphics')
port = graphics.get('port')
print port
Run Command
python vncport.py <domain name>
Here is one for the PHP version, if anyone needs this:
$res = libvirt_domain_lookup_by_name($conn, $domname);
$xmlString = libvirt_domain_get_xml_desc($res, '');
$xml = simplexml_load_string($xmlString);
$json = json_encode($xml);
$data = json_decode($json,TRUE);
$port = intval($data["devices"]["graphics"]["#attributes"]["port"]);

Resources