Trying to make a dynamic host file for ansible in python - python

This is my first post here, so if there are any questions or if something is unlcear, don't hesitate to ask.
I am trying to use a dynamic host file so I can build multiple vagrant machines without having to manage the host file first. This is what I found online:
#!/usr/bin/env python
# Adapted from Mark Mandel's implementation
# https://github.com/ansible/ansible/blob/devel/plugins/inventory/vagrant.py
import argparse
import json
import paramiko
import subprocess
import sys
def parse_args():
parser = argparse.ArgumentParser(description="Vagrant inventory script")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--list', action='store_true')
group.add_argument('--host')
return parser.parse_args()
def list_running_hosts():
cmd = "vagrant status --machine-readable"
status = subprocess.check_output(cmd.split()).rstrip()
hosts = []
for line in status.split('\n'):
(_, host, key, value) = line.split(',')
if key == 'state' and value == 'running':
hosts.append(host)
return hosts
def get_host_details(host):
cmd = "vagrant ssh-config {}".format(host)
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
config = paramiko.SSHConfig()
config.parse(p.stdout)
c = config.lookup(host)
return {'ansible_ssh_host': c['hostname'],
'ansible_ssh_port': c['port'],
'ansible_ssh_user': c['user'],
'ansible_ssh_private_key_file': c['identityfile'][0]}
def main():
args = parse_args()
if args.list:
hosts = list_running_hosts()
json.dump({'vagrant': hosts}, sys.stdout)
else:
details = get_host_details(args.host)
json.dump(details, sys.stdout)
if __name__ == '__main__':
main()
However, when I run this I get the following error:
ERROR! The file inventory/vagrant.py is marked as executable, but failed to execute correctly. If this is not supposed to be an executable script, correct this with `chmod -x inventory/vagrant.py`.
ERROR! Inventory script (inventory/vagrant.py) had an execution error: Traceback (most recent call last):
File "/home/sebas/Desktop/playbooks/inventory/vagrant.py", line 52, in <module>
main()
File "/home/sebas/Desktop/playbooks/inventory/vagrant.py", line 45, in main
hosts = list_running_hosts()
File "/home/sebas/Desktop/playbooks/inventory/vagrant.py", line 24, in list_running_hosts
(_, host, key, value) = line.split(',')
ValueError: too many values to unpack
ERROR! inventory/vagrant.py:4: Expected key=value host variable assignment, got: argparse
does anybody know what I did wrong? Thank you guys in advance!

I guess the problem is that vagrant status command will work only inside a directory with a Vagrantfile, or if the ID of a target machine is specified.
To get the state of all active Vagrant environments on the system, vagrant global-status should be used instead. But global-status has a drawback: it uses a cache and does not actively verify the state of machines.
So to reliably determine the state, first we need to get the IDs of all VMs with vagrant global-status and then check these IDs with vagrant status ID.

Related

pyvmomi deploy ovf templte

I am trying to deploy a ovf image in vcenter using the code in below link:
[https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/deploy_ovf.py][1]
python vm_deploy.py -s ‘vcneter_url’ -u ‘username’ -p ‘password’ -v ‘.vmdk path’ -f ‘.ovf path’
But it is failing with below traceback:
Traceback (most recent call last):
File "orig.py", line 218, in <module>
exit(main())
File "orig.py", line 185, in main
objs = get_objects(si, args)
File "orig.py", line 150, in get_objects
resource_pool_obj = cluster_obj.resourcePool
AttributeError: 'vim.Folder' object has no attribute 'resourcePool'
Im not able to get much help on this error online other than below link:
[https://github.com/vmware/pyvmomi-community-samples/issues/201][1]
I can see dir(cluster_obj) has no resourcePool in it but not sure how to get this working.
This script work only if you have manually created a resource pool in your architecture.
However, with a little modification you can target the default resourcePool of a specific Host.
Replace, in get_objects function, this (~line 140) :
# Get cluster object.
cluster_list = datacenter_obj.hostFolder.childEntity
if args.cluster_name:
cluster_obj = get_obj_in_list(args.cluster_name, cluster_list)
elif len(cluster_list) > 0:
cluster_obj = cluster_list[0]
else:
print "No clusters found in DC (%s)." % datacenter_obj.name
hosts = datacenter_obj.hostFolder.childEntity
resource_pool = hosts[0].resourcePool
# Generate resource pool.
resource_pool_obj = cluster_obj.resourcePool
By this :
for computeResource in datacenter_obj.hostFolder.childEntity :
if computeResource.name == 'ip or hostname here':
resource_pool = computeResource.resourcePool
break
The datacenter_obj is given, in the script that you gave, with something lik this :
datacenter_obj = si.content.rootFolder.childEntity[0]
0 is the first Datacenter found.
I hope it will help you, even if the answer comes a little late

FileNotFoundError When file exists (when created in current script)

I am trying to create a secure (e.g., SSL/HTTPS) XML-RPC Client Server. The client-server part works perfectly when the required certificates are present on my system; however, when I try to create the certificates during execution, I receive a FileNotFoundError when opening the ssl-wrapped socket even though the certificates are clearly present (because the preceding function created them.)
Why is the FileNotFoundError given when the files are present? (If I simply close and restart the python script no error is produced when opening the socket and everything works with no issue whatsoever.)
I've searched elsewhere for solutions, but the best/closest answer I've found is, perhaps, "race conditions" between creating the certificates and opening them. However, I've tried adding "sleep" to alleviate the possibility of race conditions (as well as running each function individually via a user input menu) with the same error every time.
What I am missing?
Here is a snippet of my code:
import os
import threading
import ssl
from xmlrpc.server import SimpleXMLRPCServer
import certs.gencert as gencert # <---- My python module for generating certs
...
rootDomain = "mydomain"
CERTFILE = "certs/mydomain.cert"
KEYFILE = "certs/mydomain.key"
...
def listenNow(ipAdd, portNum, serverCert, serverKey):
# Create XMLRPC Server, based on ipAdd/port received
server = SimpleXMLRPCServer((ipAdd, portNum))
# **THIS** is what causes the FileNotFoundError ONLY if
# the certificates are created during THE SAME execution
# of the program.
server.socket = ssl.wrap_socket(server.socket,
certfile=serverCert,
keyfile=serverKey,
do_handshake_on_connect=True,
server_side=True)
...
# Start server listening [forever]
server.serve_forever()
...
# Verify Certificates are present; if not present,
# create new certificates
def verifyCerts():
# If cert or key file not present, create new certs
if not os.path.isfile(CERTFILE) or not os.path.isfile(KEYFILE):
# NOTE: This [genert] will create certificates matching
# the file names listed in CERTFILE and KEYFILE at the top
gencert.gencert(rootDomain)
print("Certfile(s) NOT present; new certs created.")
else:
print("Certfiles Verified Present")
# Start a thread to run server connection as a daemon
def startServer(hostIP, serverPort):
# Verify certificates present prior to starting server
verifyCerts()
# Now, start thread
t = threading.Thread(name="ServerDaemon",
target=listenNow,
args=(hostIP,
serverPort,
CERTFILE,
KEYFILE
)
)
t.daemon = True
t.start()
if __name__ == '__main__':
startServer("127.0.0.1", 12345)
time.sleep(60) # <--To allow me to connect w/client before closing
When I run the above, with NO certificates present, this is the error I receive:
$ python3 test.py
Certfile(s) NOT present; new certs created.
Exception in thread ServerDaemon:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/usr/lib/python3.5/threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "test.py", line 41, in listenNow
server_side=True)
File "/usr/lib/python3.5/ssl.py", line 1069, in wrap_socket
ciphers=ciphers)
File "/usr/lib/python3.5/ssl.py", line 691, in __init__
self._context.load_cert_chain(certfile, keyfile)
FileNotFoundError: [Errno 2] No such file or directory
When I simply re-run the script a second time (i.e., the cert files are already present when it starts, everything runs as expected with NO errors, and I can connect my client just fine.
$ python3 test.py
Certfiles Verified Present
What is preventing the ssl.wrap_socket function from seeing/accessing the files that were just created (and thus producing the FileNotFoundError exception)?
EDIT 1:
Thanks for the comments John Gordon. Here is a copy of gencert.py, courtesy of Atul Varm, found here https://gist.github.com/toolness/3073310
import os
import sys
import hashlib
import subprocess
import datetime
OPENSSL_CONFIG_TEMPLATE = """
prompt = no
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
C = US
ST = IL
L = Chicago
O = Toolness
OU = Experimental Software Authority
CN = %(domain)s
emailAddress = varmaa#toolness.com
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = #alt_names
[ alt_names ]
DNS.1 = %(domain)s
DNS.2 = *.%(domain)s
"""
MYDIR = os.path.abspath(os.path.dirname(__file__))
OPENSSL = '/usr/bin/openssl'
KEY_SIZE = 1024
DAYS = 3650
CA_CERT = 'ca.cert'
CA_KEY = 'ca.key'
# Extra X509 args. Consider using e.g. ('-passin', 'pass:blah') if your
# CA password is 'blah'. For more information, see:
#
# http://www.openssl.org/docs/apps/openssl.html#PASS_PHRASE_ARGUMENTS
X509_EXTRA_ARGS = ()
def openssl(*args):
cmdline = [OPENSSL] + list(args)
subprocess.check_call(cmdline)
def gencert(domain, rootdir=MYDIR, keysize=KEY_SIZE, days=DAYS,
ca_cert=CA_CERT, ca_key=CA_KEY):
def dfile(ext):
return os.path.join('domains', '%s.%s' % (domain, ext))
os.chdir(rootdir)
if not os.path.exists('domains'):
os.mkdir('domains')
if not os.path.exists(dfile('key')):
openssl('genrsa', '-out', dfile('key'), str(keysize))
# EDIT 3: mydomain.key gets output here during execution
config = open(dfile('config'), 'w')
config.write(OPENSSL_CONFIG_TEMPLATE % {'domain': domain})
config.close()
# EDIT 3: mydomain.config gets output here during execution
openssl('req', '-new', '-key', dfile('key'), '-out', dfile('request'),
'-config', dfile('config'))
# EDIT 3: mydomain.request gets output here during execution
openssl('x509', '-req', '-days', str(days), '-in', dfile('request'),
'-CA', ca_cert, '-CAkey', ca_key,
'-set_serial',
'0x%s' % hashlib.md5(domain +
str(datetime.datetime.now())).hexdigest(),
'-out', dfile('cert'),
'-extensions', 'v3_req', '-extfile', dfile('config'),
*X509_EXTRA_ARGS)
# EDIT 3: mydomain.cert gets output here during execution
print "Done. The private key is at %s, the cert is at %s, and the " \
"CA cert is at %s." % (dfile('key'), dfile('cert'), ca_cert)
if __name__ == "__main__":
if len(sys.argv) < 2:
print "usage: %s <domain-name>" % sys.argv[0]
sys.exit(1)
gencert(sys.argv[1])
EDIT 2:
Regarding John's comment, "this might mean that those files are being created, but not in the directory [I] expect":
When I have the directory open in another window, I see the files pop up in the correct location during execution. In addition, when running the test.py script a second time with no changes, the files are identified as present in the correct (the same) location. This leads me to believe that file location is not the problem. Thanks for the suggestion. I'll keep looking.
EDIT 3:
I stepped through the gencert.py program, and each of the files are correctly output at the right time during execution. I indicated when exactly they were output within the above file, labeled with "EDIT 3"
While gencert is paused awaiting my input (raw_input), I can open/view/edit the mentioned files in another program with no problem.
In addition, with the first test.py instance running (paused, waiting for user input, just after mydomain.cert appears), I can run a second instance of test.py in another terminal and it sees/uses the files just fine.
Within the first instance, however, if I continue the program it outputs "FileNotFoundError."
The problem contained in the above stems from the use of os.chdir(rootdir) as suggested by John; however, the specifics are slightly different than the created files being in the wrong location. The problem is the current working directory (cwd) of the running program being changed by gencert(). Here are the specifics:
The program is started with test.py, which calls verifyCerts(). At this point the program is running in the current directory of whichever folder test.py is running inside of. Use os.getcwd() to find the current directory at this point. In this case (as an example), it is running in:
/home/name/testfolder/
Next, os.path.isfile() looks for the files "certs/mydomain.cert" and "certs/mydomain.key"; based on the file path above [e.g., the cwd], it is looking for the following files:
/home/name/testfolder/certs/mydomain.cert
/home/name/testfolder/certs/mydomain.key
The above files are not present, so the program executes gencert.gencert(rootDomain) which correctly creates both files as expected in the exact locations mentioned above in number 2.
The problem is indeed the os.chdir() call: When gencert() executes, it uses os.chdir() to change the cwd to "rootdir," which is os.path.abspath(os.path.dirname(__file__)), which is the directory of the current file (gencert.py). Since this file is located a folder deeper, the new cwd becomes:
/home/name/testfolder/certs/
When gencert() finishes execution and the control returns to test.py, the cwd never changes again; the cwd remains as /home/name/testfolder/certs/ even when execution returns to test.py.
Later, when ssl.wrap_socket() tries to find the serverCert and serverKey, it looks for "certs/mydomain.cert" and "certs/mydomain.key" in the cwd, so here is the full path of what it is looking for:
/home/name/testfolder/certs/certs/mydomain.cert
/home/name/testfolder/certs/certs/mydomain.key
These two files are NOT present, so the program correctly returns "FileNotFoundError".
Solution
A) Move the "gencert.py" file to the same directory as "test.py"
B) At the beginning of "gencert.py" add cwd = os.getcwd() to record the original cwd of the program; then, at the very end, add os.chdir(cwd) to change back to the original cwd before ending and giving control back to the calling program.
I went with option 'B', and my program now works flawlessly. I appreciate the assistance from John Gordon to point me toward finding the source of my problem.

Using nmap library in Python program

I have a simple Python program which uses nmap library to do port scanning.
from optparse import OptionParser
import nmap
from threading import *
screenLock=Semaphore(value=1)
def nmapScan(thost,tport):
x=nmap.PortScanner()
x.scan(thost,tport)
state=x[thost]['tcp'][int(tport)]['state']
print "[*]" + thost + "tcp/"+tport+" "+state
def main():
parser=OptionParser('usage %prog -H <target host> -p <target port>')
parser.add_option('-H',dest='thost',type='string',help='specify target host')
parser.add_option('-p',dest='tports',type='string',help='specify target port[s] seperated by comma')
(options,args)=parser.parse_args()
thost=options.thost
tports=options.tports
tports=tports.split(',')
if (thost==None)|(tports==None):
print parser.usage
exit(0)
for i in tports:
nmapScan(thost,i)
main()
When i run the program, i get the following error.
akshayrajmacbookpro$ python nmapScanner.py -H 192.168.1.60 -p 80,443
Traceback (most recent call last):
File "nmapScanner.py", line 28, in <module>
main()
File "nmapScanner.py", line 26, in main
nmapScan(thost,i)
File "nmapScanner.py", line 10, in nmapScan
state=x[thost]['tcp'][int(tport)]['state']
File "build/bdist.macosx-10.11-intel/egg/nmap/nmap.py", line 555, in __getitem__
KeyError: '192.168.1.60'
I tried using url instead of ip in the command line. But I get the same error. Being new to Python, I am not able to understand and resolve this.
x (instance of nmap.PortScanner) does not contain those keys. To be able to iterate the scan results you can do this:
for host, result in x._scan_result['scan'].items():
print "[*]" + thost + "tcp/" + tport + " " + result['status']['state']
It's best if you looked at the docs or source code of python-nmap to see what other useful info is available e.g. Service name and version that is listening on that port.
More info here: https://bitbucket.org/xael/python-nmap/src/f368486a2cf12ce2bf3d5978614586e89c49c417/nmap/nmap.py?at=default&fileviewer=file-view-default#nmap.py-381
The host does not exist in the result of the scan as a "Key" for the Dictionary that forms a part of the data thrown up by scan data. That is probably, in my opinion, the reason for the error. Thanks

Use REMOTE_ADDR in an other file [duplicate]

This question already exists:
How can I display environment variable [duplicate]
Closed 8 years ago.
I code in python and I have a problem.
I have file1.py :
import os, sys, platform, getpass, tempfile
import webbrowser
import string
import json
import cgi, cgitb
def main( addr, name):
os.environ["REMOTE_ADDR"] = addr
print os.environ ["REMOTE_ADDR"]
template = open('file2.py').read()
tmpl = string.Template(template).substitute(
name = name,
addr = cgi.escape(os.environ["REMOTE_ADDR"]),
os = user_os,
user_name = user_login,
)
f = tempfile.NamedTemporaryFile(prefix='/tmp/info.html', mode='w', delete=False)
f.write(contenu)
f.close()
webbrowser.open(f.name)
if __name__ == "__main__":
addr = sys.argv[1]
name = sys.argv[2]
user_os = sys.platform
sys.argv.append(user_os)
user_login = getpass.getuser()
sys.argv.append(user_login)
main(addr, name)
in the file2.py
<form name="sD" method="get" action="${addr}">
but I have this error and I have tried to resolve it, but I don't know how can do that :(
Traceback (most recent call last):
File "./file1.py", line 47, in <module>
main(addr, name)
File "./file1.py", line 22, in main
addr = cgi.escape(os.environ["REMOTE_ADDR"])
File "/usr/lib/python2.6/UserDict.py", line 22, in __getitem__
raise KeyError(key)
KeyError: 'REMOTE_ADDR'
My problem is, I don't know how can I put a addr variable in command line and recover that IP address in an URL when I click on the OK button
Help me please :(
You have multiple problems with your code.
First, as mentioned in your previous question:
you dont (I repeat: you dont) want the IP of the client as the url for
your form's action
What, exactly, do you think this line of code is going to do?
<form name="sD" method="get" action="${addr}">
It will attempt to send the form to your end user's IP address. This will fail. This will fail because
They likely don't have a web server running
Even if they do, they likely don't have a script built to handle your form
You should be submitting the form to a page you control so that you can process it
As for your missing key error, you don't have an environment variable set. You can do this a few ways:
From outside of your python script, use this command: set REMOTE_ADDR=<value>. Replace <value> with an appropriate value.
From within your python script, use this code
Remember to import os
import os
os.environ["REMOTE_ADDR"] = "value"
Again, value should be an appropriate value.
A very simple example of what you want:
import os, sys
def main( addr, name):
os.environ["REMOTE_ADDR"] = addr
print os.environ["REMOTE_ADDR"]
if __name__ == "__main__":
addr = sys.argv[1]
name = sys.argv[2]
main(addr, name)
This outputs:
>python test.py "address" "name"
address
>python test.py "http://www.google.com" "name"
http://www.google.com
Finally, as mentioned in your previous question:
you dont (I repeat: you dont) want the IP of the client as the url for
your form's action
From your shell (i.e. command line)
$> set REMOTE_ADDR=<some url>
$> python
>>> import os
>>> print os.environ['REMOTE_ADDR']
<some url>
if you define it in the python instance it is only available to that instance
but by putting in the 'environment' before calling any module it is 'globally' available

Python import error

I am trying to run a python file from the command line with a single parameter in Ubuntu 12.04. The program works if I simply run it from the IDE and pass the parameter in the code. However, if I call 'python readFromSerial1.py 3' in the command prompt, I get:
Traceback (most recent call last):
File "readFromSerial1.py", line 62, in <module>
main()
File "readFromSerial1.py", line 6, in main
readDataFromUSB(time)
File "readFromSerial1.py", line 9, in readDataFromUSB
import usb.core
ImportError: No module named usb.core
I'm a little confused as the module imports correctly if I run from the IDE. I download the pyUSB module and extracted it (its filename is pyusb-1.0.0a3). I then copied this file into
/usr/local/lib/python2.7/site-packages/. Is that the correct procedure? I have a feeling the issue is due to python simply not being able to find the usb module and I need to put it in the correct location. My code is below, and any help would be greatly appreciated:
readFromSerial1.py
import sys
def main():
time = sys.argv[1]
#time = 1
readDataFromUSB(time)
def readDataFromUSB(time):
import usb.core
#find device
dev = usb.core.find(idVendor=0x099e, idProduct=0x0001) #GPS info
#Was the device found?
if dev is None:
raise ValueError('Device not found')
else:
print "Device found!"
#Do this to avoid 'Errno16: Resource is busy'
if dev.is_kernel_driver_active(0):
try:
dev.detach_kernel_driver(0)
except usb.core.USBError as e:
sys.exit("Could not detach kernel driver: %s" % str(e))
#Sets default config
dev.set_configuration()
#Gets default endpoint
endpoint = dev[0][(0,0)][0]
writeObject = open("InputData.txt", "w")
#iterate for time purposes
for i in range(0, (time*6)): #sys.argv is command line variable for time input
data = dev.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, 0, 100000)
sret = ''.join([chr(x) for x in data])
writeObject.write(sret);
print sret
'''
newStr = ''.join(sret[7:14])
compareStr = ",*4F"
if (newStr == compareStr):
print "The GPS is not reading in any values right now. Try going somewhere else with better reception."
else:
print sret[7:14]
'''
writeObject.close()
main()

Categories