cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chirad...@apache.org
Subject [01/11] git commit: Add support for using username and password to cloudmonkey. The interactive CLI user can call 'login' and 'logout' to start and terminate a session. If the apikey and secretkey are not supplied in the config, then the username and pas
Date Wed, 23 Apr 2014 23:59:13 GMT
Repository: cloudstack-cloudmonkey
Updated Branches:
  refs/heads/master a711367e4 -> fc5d85da2


Add support for using username and password to cloudmonkey.
The interactive CLI user can call 'login' and 'logout' to start and terminate a session.
If the apikey and secretkey are not supplied in the config, then the username and password
are used.
If the session has expired, the CLI will automatically login and obtain a session


Project: http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/commit/61901f20
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/tree/61901f20
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/diff/61901f20

Branch: refs/heads/master
Commit: 61901f20d23383589582620779ad55034b08c0a0
Parents: 34665b3
Author: Chiradeep Vittal <chiradeep@apache.org>
Authored: Tue Oct 15 19:21:26 2013 -0700
Committer: Chiradeep Vittal <chiradeep@apache.org>
Committed: Tue Oct 15 19:21:26 2013 -0700

----------------------------------------------------------------------
 cloudmonkey/cloudmonkey.py |  28 ++++++++++-
 cloudmonkey/config.py      |   2 +
 cloudmonkey/requester.py   | 108 +++++++++++++++++++++++++++++++++++++---
 3 files changed, 131 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/blob/61901f20/cloudmonkey/cloudmonkey.py
----------------------------------------------------------------------
diff --git a/cloudmonkey/cloudmonkey.py b/cloudmonkey/cloudmonkey.py
index b465bec..53ca066 100644
--- a/cloudmonkey/cloudmonkey.py
+++ b/cloudmonkey/cloudmonkey.py
@@ -36,6 +36,8 @@ try:
     from prettytable import PrettyTable
     from printer import monkeyprint
     from requester import monkeyrequest
+    from requester import login
+    from requester import logout
 except ImportError, e:
     print("Import error in %s : %s" % (__name__, e))
     import sys
@@ -73,6 +75,8 @@ class CloudMonkeyShell(cmd.Cmd, object):
         self.config_file = cfile
         self.config_options = read_config(self.get_attr, self.set_attr,
                                           self.config_file)
+        self.credentials = {'apikey':self.apikey, 'secretkey': self.secretkey, 
+                            'username': self.username, 'password': self.password}
         self.loadcache()
         self.prompt = self.prompt.strip() + " "  # Cosmetic fix for prompt
 
@@ -90,6 +94,7 @@ class CloudMonkeyShell(cmd.Cmd, object):
             logger.debug("Error: Unable to read history. " + str(e))
         atexit.register(readline.write_history_file, self.history_file)
 
+
     def get_attr(self, field):
         return getattr(self, field)
 
@@ -253,7 +258,7 @@ class CloudMonkeyShell(cmd.Cmd, object):
         response, error = monkeyrequest(command, args, isasync,
                                         self.asyncblock, logger,
                                         self.host, self.port,
-                                        self.apikey, self.secretkey,
+                                        self.credentials,
                                         self.timeout, self.protocol, self.path)
         if error is not None:
             self.monkeyprint(error)
@@ -414,6 +419,25 @@ class CloudMonkeyShell(cmd.Cmd, object):
         return [s[offs:] for s in self.config_options
                 if s.startswith(mline)]
 
+    def do_login(self, args):
+        """
+        Login using stored credentials. Starts a session to be reused for subsequent api
calls
+        """
+        url = "%s://%s:%s%s" % (self.protocol, self.host, self.port, self.path)
+        session, sessionkey = login(url, self.username, self.password)
+        self.credentials['session'] = session
+        self.credentials['sessionkey'] = sessionkey
+
+    def do_logout(self, args):
+        """
+        Logout of session started with login with username and password
+        """
+        url = "%s://%s:%s%s" % (self.protocol, self.host, self.port, self.path)
+        logout(url, self.credentials['session'])
+        self.credentials['session'] = None
+        self.credentials['sessionkey'] = None
+
+
     def pipe_runner(self, args):
         if args.find(' |') > -1:
             pname = self.program_name
@@ -529,7 +553,9 @@ def main():
         print __description__, "(%s)" % __projecturl__
         sys.exit(0)
 
+
     shell = CloudMonkeyShell(sys.argv[0], options.cfile)
+
     if len(args) > 0:
         shell.onecmd(' '.join(args))
     else:

http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/blob/61901f20/cloudmonkey/config.py
----------------------------------------------------------------------
diff --git a/cloudmonkey/config.py b/cloudmonkey/config.py
index 2f91608..ae56bfa 100644
--- a/cloudmonkey/config.py
+++ b/cloudmonkey/config.py
@@ -66,6 +66,8 @@ config_fields['server']['timeout'] = '3600'
 # user
 config_fields['user']['apikey'] = ''
 config_fields['user']['secretkey'] = ''
+config_fields['user']['username'] = ''
+config_fields['user']['password'] = ''
 
 
 def write_config(get_attr, config_file, first_time=False):

http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/blob/61901f20/cloudmonkey/requester.py
----------------------------------------------------------------------
diff --git a/cloudmonkey/requester.py b/cloudmonkey/requester.py
index b06e1fc..93400e1 100644
--- a/cloudmonkey/requester.py
+++ b/cloudmonkey/requester.py
@@ -26,6 +26,7 @@ try:
     import os
     import pdb
     import re
+    import requests
     import shlex
     import sys
     import time
@@ -45,8 +46,95 @@ def logger_debug(logger, message):
         logger.debug(message)
 
 
+def login(url, username, password):
+    """
+    Login and obtain a session to be used for subsequent API calls
+    Wrong username/password leads to HTTP error code 531
+    """
+    args = {}
+
+    args["command"] = 'login'
+    args["username"] = username
+    args["password"] = password
+    args["domain"] = "/"
+    args["response"] = "json"
+
+    sessionkey = ''
+    session = requests.Session()
+
+    resp = session.post(url, params=args)
+    if resp.status_code == 200:
+        sessionkey = resp.json()['loginresponse']['sessionkey']
+        userid = resp.json()['loginresponse']['userid']
+    elif resp.status_code == 531:
+        print "Error authenticating at %s, with username: %s, and password: %s" % (url, username,
password)
+        session = None
+        sessionkey = None
+    else:
+        resp.raise_for_status()
+
+
+    return session, sessionkey
+
+
+def logout(url, session):
+    if session is None:
+        return
+    session.get(url, params={'command': 'logout'})
+
+def make_request_with_password(command, args, logger, url, credentials):
+
+    error = None
+    username = credentials['username']
+    password = credentials['password']
+
+    if not (username and password):
+        error = "Username and password cannot be empty"
+        result = None
+        return result, error
+
+    tries = 0
+    retry = True
+
+    while tries < 2 and retry:
+        sessionkey = credentials.get('sessionkey')
+        session = credentials.get('session')
+        tries += 1
+    
+        #obtain a valid session if not supplied
+        if not (session and sessionkey):
+            session, sessionkey = login(url, username, password)
+            if not (session and sessionkey):
+                return None, 'Error authenticating'
+            credentials['session'] = session
+            credentials['sessionkey'] = sessionkey
+
+        args['sessionkey'] = sessionkey
+    
+        #make the api call
+        resp = session.get(url, params=args)
+        result = resp.text
+        logger_debug(logger, "Response received: %s" % resp.text)
+
+        if resp.status_code == 200: #success
+            retry = False
+            break
+        if resp.status_code == 401: #sessionkey is wrong
+            credentials['session'] = None
+            credentials['sessionkey'] = None
+            continue
+
+        if resp.status_code != 200 and resp.status_code != 401:
+            error = "%s: %s" % (str(resp.status_code), resp.headers.get('X-Description'))
+            result = None
+            retry = False
+            
+
+    return result, error
+
+
 def make_request(command, args, logger, host, port,
-                 apikey, secretkey, protocol, path):
+                 credentials, protocol, path):
     response = None
     error = None
 
@@ -58,8 +146,16 @@ def make_request(command, args, logger, host, port,
         args = {}
 
     args["command"] = command
-    args["apiKey"] = apikey
     args["response"] = "json"
+
+    #try to use the apikey/secretkey method by default
+    #if not present, use the username/password method
+    if not credentials['apikey']:
+        url = "%s://%s:%s%s" % (protocol, host, port, path)
+        return make_request_with_password(command, args, logger, url, credentials)
+
+    args['apikey'] = credentials['apikey']
+    secretkey = credentials['secretkey']
     request = zip(args.keys(), args.values())
     request.sort(key=lambda x: x[0].lower())
 
@@ -92,13 +188,13 @@ def make_request(command, args, logger, host, port,
 
 
 def monkeyrequest(command, args, isasync, asyncblock, logger, host, port,
-                  apikey, secretkey, timeout, protocol, path):
+                  credentials, timeout, protocol, path):
     response = None
     error = None
     logger_debug(logger, "======== START Request ========")
     logger_debug(logger, "Requesting command=%s, args=%s" % (command, args))
-    response, error = make_request(command, args, logger, host, port,
-                                   apikey, secretkey, protocol, path)
+    response, error = make_request(command, args, logger, host, port, credentials, protocol,
path)
+
     logger_debug(logger, "======== END Request ========\n")
 
     if error is not None:
@@ -135,7 +231,7 @@ def monkeyrequest(command, args, isasync, asyncblock, logger, host, port,
             progress += 1
             logger_debug(logger, "Job %s to timeout in %ds" % (jobid, timeout))
             response, error = make_request(command, request, logger,
-                                           host, port, apikey, secretkey,
+                                           host, port, credentials,
                                            protocol, path)
             if error is not None:
                 return response, error


Mime
View raw message