Permalink
Browse files

Initial supernova-keyring support

Added basic get/set password functionality for any abitrary configuration parameter for any environment
Added bin/supernova-keyring
Added entry_point in setuptools for supernova-keyring executable
Minor code cleanup
  • Loading branch information...
major committed Jun 2, 2012
1 parent 8606c92 commit c3d14593f697a83192f4a1a85c70f0c4db107875
Showing with 151 additions and 2 deletions.
  1. +34 −0 bin/supernova-keyring
  2. +3 −1 setup.py
  3. +92 −0 supernova/executable.py
  4. +22 −1 supernova/supernova.py
View
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Major Hayden
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# ----
+#
+# This file only exists to help with local testing prior to installation.
+# The actual supernova executable in your bin directory will be created by
+# setuptools (see entry_points in setup.py).
+#
+import os
+import sys
+
+
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+ os.pardir,
+ os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'supernova', '__init__.py')):
+ sys.path.insert(0, possible_topdir)
+
+from supernova import executable
+executable.run_supernova_keyring()
View
@@ -27,6 +27,8 @@
packages=['supernova'],
url='https://github.com/rackerhacker/supernova',
entry_points={
- 'console_scripts': ['supernova = supernova.executable:run_supernova']
+ 'console_scripts': [
+ 'supernova = supernova.executable:run_supernova',
+ 'supernova-keyring = supernova.executable:run_supernova_keyring'],
}
)
View
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+import getpass
import optparse
import supernova
import sys
@@ -99,3 +100,94 @@ def run_supernova():
# All of the remaining arguments should be handed off to nova
novaclient_args = args[1:]
s.run_novaclient(novaclient_args, opts.debug)
+
+
+def run_supernova_keyring():
+ """
+ Handles all of the prep work and error checking for the
+ supernova-keyring executable.
+ """
+ s = supernova.SuperNova()
+ parser = optparse.OptionParser()
+ parser.add_option('-g', '--get', action="store_true",
+ dest="get_password", default=False,
+ help='retrieves credentials from keychain storage')
+ parser.add_option('-s', '--set', action="store_true",
+ dest="set_password", default=False,
+ help='stores credentials in keychain storage')
+ (opts, args) = parser.parse_args()
+
+ if opts.get_password and opts.set_password:
+ print "[%s] You asked to get and set a password at the same time. " \
+ "This is not supported." % rwrap("Too many options")
+
+ # No matter what, we need two arguments: environment and a
+ # configuration option
+ if len(args) != 2:
+ print "[%s] Usage: supernova-keyring [--get | --set] " \
+ "environment parameter" % rwrap("Invalid number of arguments")
+ sys.exit()
+
+ username = "%s:%s" % (args[0], args[1])
+
+ if opts.set_password:
+ print "[%s] Preparing to set a password in the keyring for:" % (
+ gwrap("Keyring operation"))
+ print " - Environment : %s" % args[0]
+ print " - Parameter : %s" % args[1]
+ print "\n If this is correct, enter the corresponding credential " \
+ "to store in \n your keyring or press CTRL-D to abort: ",
+
+ # Prompt for a password and catch a CTRL-D
+ try:
+ password = getpass.getpass('')
+ except:
+ password = None
+ print
+
+ # Did we get a password from the prompt?
+ if not password or len(password) < 1:
+ print "\n[%s] No data was altered in your keyring." % (
+ rwrap("Canceled"))
+ sys.exit()
+
+ # Try to store the password
+ try:
+ store_ok = s.password_set(username, password)
+ except:
+ store_ok = False
+
+ if store_ok:
+ print "\n[%s] Successfully stored credentials for %s under the " \
+ "supernova service." % (gwrap("Success"), username)
+ else:
+ print "\n[%s] Unable to store credentials for %s under the " \
+ "supernova service." % rwrap("Failed", username)
+
+ sys.exit()
+
+ if opts.get_password:
+ print "[%s] If this operation is successful, the credential " \
+ "stored \n for %s will be displayed in your terminal as " \
+ "plain text." % (rwrap("Warning"), username)
+ print "\nIf you really want to proceed, type yes and press enter:",
+ confirm = raw_input('')
+
+ if confirm != 'yes':
+ print "\n[%s] Your keyring was not read or altered." % (
+ rwrap("Canceled"))
+ sys.exit()
+
+ try:
+ password = s.password_get(username)
+ except:
+ password = None
+
+ if password:
+ print "\n[%s] Found credentials for %s: %s" % (
+ gwrap("Success"), username, password)
+ else:
+ print "\n[%s] Unable to retrieve credentials for %s.\nThere are " \
+ "probably no credentials stored for this environment/" \
+ "parameter combination (try --set)." % (
+ rwrap("Failed"), username)
View
@@ -15,6 +15,7 @@
# limitations under the License.
#
import ConfigParser
+import keyring
import os
import re
import subprocess
@@ -29,7 +30,6 @@ def __init__(self):
self.nova_creds = None
self.nova_env = None
self.env = os.environ
- pass
def check_deprecated_options(self):
"""
@@ -65,6 +65,27 @@ def is_valid_environment(self):
valid_envs = self.get_nova_creds().sections()
return self.nova_env in valid_envs
+ def password_get(self, username=None):
+ """
+ Retrieves a password from the keychain based on the environment and
+ configuration parameter pair.
+ """
+ try:
+ return keyring.get_password('supernova', username)
+ except:
+ return False
+
+ def password_set(self, username=None, password=None):
+ """
+ Stores a password in a keychain for a particular environment and
+ configuration parameter pair.
+ """
+ try:
+ keyring.set_password('supernova', username, password)
+ return True
+ except:
+ return False
+
def prep_nova_creds(self):
"""
Finds relevant config options in the supernova config and cleans them

0 comments on commit c3d1459

Please sign in to comment.