Skip to content

Commit

Permalink
Added basic authentication support
Browse files Browse the repository at this point in the history
- Fixed issue when adding resource/stonith and crm_mon error occurs
- Added ability to get cluster status xml
- Bumped version to 0.9.5
  • Loading branch information
feist committed Jun 11, 2012
1 parent 7887f49 commit 02d848a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 4 deletions.
23 changes: 23 additions & 0 deletions pcs/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def cluster_cmd(argv):
sync_nodes(utils.getNodesFromCorosyncConf(),utils.getCorosyncConf())
elif (sub_cmd == "gui-status"):
cluster_gui_status(argv)
elif (sub_cmd == "auth"):
cluster_auth(argv)
elif (sub_cmd == "start"):
start_cluster(argv)
elif (sub_cmd == "stop"):
Expand Down Expand Up @@ -57,6 +59,25 @@ def sync_nodes(nodes,config):
for node in nodes:
utils.setCorosyncConfig(node,config)

def cluster_auth(argv):
if len(argv) == 0:
auth_nodes(utils.getNodesFromCorosyncConf())
else:
auth_nodes(argv)

def auth_nodes(nodes):
for node in nodes:
status = utils.checkStatus(node)
if status[0] == 0:
print node + ": Already authorized"
elif status[0] == 3:
utils.updateToken(node)
print "%s: Authorized" % (node)
else:
print "Unable to communicate with %s" % (node)
exit(1)


# If no arguments get current cluster node status, otherwise get listed
# nodes status
def cluster_gui_status(argv):
Expand All @@ -71,6 +92,8 @@ def check_nodes(nodes):
status = utils.checkStatus(node)
if status[0] == 0:
print node + ": Online"
elif status[0] == 3:
print node + ": Unable to authenticate"
else:
print node + ": Offline"

Expand Down
2 changes: 2 additions & 0 deletions pcs/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ def resource_create(ra_id, ra_type, ra_values, op_values):
output,retval = utils.run(args)
if retval != 0:
print "ERROR: Unable to create resource/fence device"
print output.split('\n')[0]
sys.exit(1)

# Update a resource, removing any args that are empty and adding/updating
# args that are not empty
Expand Down
9 changes: 9 additions & 0 deletions pcs/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def status_cmd(argv):
nodes_status(argv)
elif (sub_cmd == "actions"):
actions_status(argv)
elif (sub_cmd == "xml"):
xml_status()
else:
usage.status()
sys.exit(1)
Expand Down Expand Up @@ -144,3 +146,10 @@ def cluster_status(argv):
break

print "",line
def xml_status():
(output, retval) = utils.run(["/usr/sbin/crm_mon", "-1", "-r", "-X"])

if (retval != 0):
print "Error running crm_mon, is pacemaker running?"
sys.exit(1)
print output
13 changes: 11 additions & 2 deletions pcs/usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,15 @@ def cluster():
stop Stop corosync & pacemaker
startall Start corosync & pacemaker on all nodes
stopall Stop corosync & pacemaker on all nodes
gui-status [node] [...]
gui-status [node] [...]
Get current status of pcs-gui on nodes specified, or on all nodes
configure in corosync.conf if no nodes are specified
configured in corosync.conf if no nodes are specified
auth [node] [...]
Authenticate pcs to pcs-gui on nodes specified, or on all nodes
configured in corosync.conf if no nodes are specified (authorization
tokens are stored in ~/.pcs/token)
sync
Sync corosync configuration to all nodes found from current
Expand Down Expand Up @@ -199,4 +205,7 @@ def status():
status actions
View failed actions
status xml
View xml version of status (output from crm_mon -r -1 -X)
"""
58 changes: 56 additions & 2 deletions pcs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import urllib,urllib2
from xml.dom.minidom import parseString
import re
import getpass
import json


# usefile & filename variables are set in pcs module
Expand All @@ -16,6 +18,44 @@ def checkStatus(node):
out = sendHTTPRequest(node, 'remote/status', None, False)
return out

def updateToken(node):
username = raw_input(node + " username: ")
password = getpass.getpass(node + " password: ")
data = urllib.urlencode({'username':username, 'password':password})
out = sendHTTPRequest(node, 'remote/auth', data, False)
if out[0] != 0:
print "ERROR: Unable to connect to pcs-gui on %s" % node
print out
exit(1)
token = out[1]
if token == "":
print "ERROR: Username and/or password is incorrect"
exit(1)

tokens = readTokens()
tokens[node] = token
writeTokens(tokens)

return True

# Returns a dictionary {'nodeA':'tokenA'}
def readTokens():
tokenfile = os.path.expanduser("~/.pcs/tokens")
if (os.path.isfile(tokenfile) == False):
return {}
tokens = json.load(open(tokenfile))
return tokens

# Takes a dictionary {'nodeA':'tokenA'}
def writeTokens(tokens):
tokenfile = os.path.expanduser("~/.pcs/tokens")
if (os.path.isfile(tokenfile) == False):
if not os.path.exists(os.path.expanduser("~/.pcs")):
os.mkdir(os.path.expanduser("~/.pcs"),0700);
f = os.fdopen (os.open(tokenfile, os.O_WRONLY | os.O_CREAT, 0600), 'w')
f.write(json.dumps(tokens))
f.close()

# Set the corosync.conf file on the specified node
def setCorosyncConfig(node,config):
data = urllib.urlencode({'corosync_conf':config})
Expand All @@ -30,9 +70,17 @@ def stopCluster(node):
# Send an HTTP request to a node return a tuple with status, data
# If status is 0 then data contains server response
# Otherwise if non-zero then data contains error message
# Returns a tuple (error, error message)
# 0 = Success,
# 1 = HTTP Error
# 2 = No response,
# 3 = Auth Error
def sendHTTPRequest(host, request, data = None, printResult = True):
url = 'http://' + host + ':2222/' + request
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
tokens = readTokens()
if host in tokens:
opener.addheaders.append(('Cookie', 'token='+tokens[host]))
urllib2.install_opener(opener)
try:
result = opener.open(url,data)
Expand All @@ -42,8 +90,14 @@ def sendHTTPRequest(host, request, data = None, printResult = True):
return (0,html)
except urllib2.HTTPError, e:
if printResult:
print "Error connecting to %s - (HTTP error: %d)" % (host,e.code)
return (1,"Error connecting to %s - (HTTP error: %d)" % (host,e.code))
if e.code == 401:
print "Unable to authenticate to %s - (HTTP error: %d)" % (host,e.code)
else:
print "Error connecting to %s - (HTTP error: %d)" % (host,e.code)
if e.code == 401:
return (3,"Unable to authenticate to %s - (HTTP error: %d)" % (host,e.code))
else:
return (1,"Error connecting to %s - (HTTP error: %d)" % (host,e.code))
except urllib2.URLError, e:
if printResult:
print "Unable to connect to %s (%s)" % (host, e.reason)
Expand Down

0 comments on commit 02d848a

Please sign in to comment.