Add authentication in fuel-cli
* modified APIClient to get token * modified base test class for fuel-cli to mock keystone authentication * modified fuel-cli to use user and password Change-Id: I4b0a2dc485c086949b103c11689ea892069f02e5 Implements: blueprint access-control-master-node
This commit is contained in:
@@ -46,6 +46,11 @@ class Action(object):
|
||||
"""Entry point for all actions subclasses
|
||||
"""
|
||||
APIClient.debug_mode(debug=params.debug)
|
||||
if getattr(params, 'user') and getattr(params, 'password'):
|
||||
APIClient.user = params.user
|
||||
APIClient.password = params.password
|
||||
APIClient.initialize_keystone_client()
|
||||
|
||||
self.serializer = Serializer.from_params(params)
|
||||
if self.flag_func_map is not None:
|
||||
for flag, method in self.flag_func_map:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from functools import wraps
|
||||
from keystoneclient.exceptions import Unauthorized
|
||||
import sys
|
||||
import urllib2
|
||||
|
||||
@@ -77,6 +78,8 @@ def handle_exceptions(exc):
|
||||
))
|
||||
elif isinstance(exc, urllib2.URLError):
|
||||
exit_with_error("Can't connect to Nailgun server!")
|
||||
elif isinstance(exc, Unauthorized):
|
||||
exit_with_error("Unauthorized: need authentication!")
|
||||
elif isinstance(exc, FuelClientException):
|
||||
exit_with_error(exc.message)
|
||||
else:
|
||||
|
||||
@@ -44,6 +44,7 @@ class Parser:
|
||||
self.generate_actions()
|
||||
self.add_version_args()
|
||||
self.add_debug_arg()
|
||||
self.add_keystone_credentials_args()
|
||||
self.add_serializers_args()
|
||||
|
||||
def generate_actions(self):
|
||||
@@ -101,6 +102,26 @@ class Parser:
|
||||
default=False
|
||||
)
|
||||
|
||||
def add_keystone_credentials_args(self):
|
||||
self.universal_flags.append("--os-username")
|
||||
self.parser.add_argument(
|
||||
"--os-username",
|
||||
dest="user",
|
||||
action="store",
|
||||
type=str,
|
||||
help="credentials for keystone authentication user",
|
||||
default=None
|
||||
)
|
||||
self.universal_flags.append("--os-password")
|
||||
self.parser.add_argument(
|
||||
"--os-password",
|
||||
dest="password",
|
||||
action="store",
|
||||
type=str,
|
||||
help="credentials for keystone authentication password",
|
||||
default=None
|
||||
)
|
||||
|
||||
def add_version_args(self):
|
||||
for args in (get_version_arg(), get_fuel_version_arg()):
|
||||
self.parser.add_argument(*args["args"], **args["params"])
|
||||
|
||||
@@ -18,6 +18,8 @@ import urllib2
|
||||
|
||||
import yaml
|
||||
|
||||
from keystoneclient import client as auth_client
|
||||
|
||||
from fuelclient.cli.error import exceptions_decorator
|
||||
|
||||
|
||||
@@ -27,10 +29,14 @@ class Client(object):
|
||||
|
||||
def __init__(self):
|
||||
self.debug = False
|
||||
path_to_config = "/etc/fuel-client.yaml"
|
||||
self.test_mod = bool(os.environ.get('TEST_MODE', ''))
|
||||
path_to_config = "/etc/fuel/client/config.yaml"
|
||||
defaults = {
|
||||
"LISTEN_ADDRESS": "127.0.0.1",
|
||||
"LISTEN_PORT": "8000"
|
||||
"SERVER_ADDRESS": "127.0.0.1",
|
||||
"LISTEN_PORT": "8000",
|
||||
"KEYSTONE_USER": "admin",
|
||||
"KEYSTONE_PASS": "admin",
|
||||
"KEYSTONE_PORT": "5000",
|
||||
}
|
||||
if os.path.exists(path_to_config):
|
||||
with open(path_to_config, "r") as fh:
|
||||
@@ -38,9 +44,34 @@ class Client(object):
|
||||
defaults.update(config)
|
||||
else:
|
||||
defaults.update(os.environ)
|
||||
self.root = "http://{LISTEN_ADDRESS}:{LISTEN_PORT}".format(**defaults)
|
||||
self.root = "http://{SERVER_ADDRESS}:{LISTEN_PORT}".format(**defaults)
|
||||
self.keystone_base = (
|
||||
"http://{SERVER_ADDRESS}:{LISTEN_PORT}/keystone/v2.0"
|
||||
.format(**defaults)
|
||||
)
|
||||
self.api_root = self.root + "/api/v1/"
|
||||
self.ostf_root = self.root + "/ostf/"
|
||||
self.auth_status()
|
||||
self.user = defaults["KEYSTONE_USER"]
|
||||
self.password = defaults["KEYSTONE_PASS"]
|
||||
self.keystone_client = None
|
||||
self.initialize_keystone_client()
|
||||
|
||||
def auth_status(self):
|
||||
self.auth_required = False
|
||||
if not self.test_mod:
|
||||
request = urllib2.urlopen(''.join([self.api_root, 'version']))
|
||||
self.auth_required = json.loads(
|
||||
request.read()).get('auth_required', False)
|
||||
|
||||
def initialize_keystone_client(self):
|
||||
if not self.test_mod and self.auth_required:
|
||||
self.keystone_client = auth_client.Client(
|
||||
username=self.user,
|
||||
password=self.password,
|
||||
auth_url=self.keystone_base,
|
||||
tenant_name="admin")
|
||||
self.keystone_client.authenticate()
|
||||
|
||||
def debug_mode(self, debug=False):
|
||||
self.debug = debug
|
||||
@@ -53,12 +84,14 @@ class Client(object):
|
||||
def delete_request(self, api):
|
||||
"""Make DELETE request to specific API with some data
|
||||
"""
|
||||
token = self.keystone_client.auth_token if self.keystone_client else ''
|
||||
self.print_debug(
|
||||
"DELETE {0}".format(self.api_root + api)
|
||||
)
|
||||
opener = urllib2.build_opener(urllib2.HTTPHandler)
|
||||
request = urllib2.Request(self.api_root + api)
|
||||
request.add_header('Content-Type', 'application/json')
|
||||
request.add_header('X-Auth-Token', token)
|
||||
request.get_method = lambda: 'DELETE'
|
||||
opener.open(request)
|
||||
return {}
|
||||
@@ -66,6 +99,7 @@ class Client(object):
|
||||
def put_request(self, api, data):
|
||||
"""Make PUT request to specific API with some data
|
||||
"""
|
||||
token = self.keystone_client.auth_token if self.keystone_client else ''
|
||||
data_json = json.dumps(data)
|
||||
self.print_debug(
|
||||
"PUT {0} data={1}"
|
||||
@@ -74,6 +108,7 @@ class Client(object):
|
||||
opener = urllib2.build_opener(urllib2.HTTPHandler)
|
||||
request = urllib2.Request(self.api_root + api, data=data_json)
|
||||
request.add_header('Content-Type', 'application/json')
|
||||
request.add_header('X-Auth-Token', token)
|
||||
request.get_method = lambda: 'PUT'
|
||||
return json.loads(
|
||||
opener.open(request).read()
|
||||
@@ -82,19 +117,23 @@ class Client(object):
|
||||
def get_request(self, api, ostf=False):
|
||||
"""Make GET request to specific API
|
||||
"""
|
||||
token = self.keystone_client.auth_token if self.keystone_client else ''
|
||||
url = (self.ostf_root if ostf else self.api_root) + api
|
||||
self.print_debug(
|
||||
"GET {0}"
|
||||
.format(url)
|
||||
)
|
||||
request = urllib2.urlopen(url)
|
||||
opener = urllib2.build_opener(urllib2.HTTPHandler)
|
||||
request = urllib2.Request(url)
|
||||
request.add_header('X-Auth-Token', token)
|
||||
return json.loads(
|
||||
request.read()
|
||||
opener.open(request).read()
|
||||
)
|
||||
|
||||
def post_request(self, api, data, ostf=False):
|
||||
"""Make POST request to specific API with some data
|
||||
"""
|
||||
token = self.keystone_client.auth_token if self.keystone_client else ''
|
||||
url = (self.ostf_root if ostf else self.api_root) + api
|
||||
data_json = json.dumps(data)
|
||||
self.print_debug(
|
||||
@@ -108,6 +147,7 @@ class Client(object):
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
)
|
||||
request.add_header('X-Auth-Token', token)
|
||||
try:
|
||||
response = json.loads(
|
||||
urllib2.urlopen(request)
|
||||
|
||||
@@ -23,3 +23,4 @@ simplejson==3.3.0
|
||||
web.py==0.37
|
||||
wsgilog==0.3
|
||||
wsgiref==0.1.2
|
||||
python-keystoneclient>=0.7
|
||||
|
||||
@@ -102,6 +102,7 @@ class BaseTestCase(TestCase):
|
||||
|
||||
def run_cli_command(self, command_line, check_errors=False):
|
||||
modified_env = os.environ.copy()
|
||||
modified_env['TEST_MODE'] = 'True'
|
||||
command_args = [" ".join((self.fuel_path, command_line))]
|
||||
process_handle = subprocess.Popen(
|
||||
command_args,
|
||||
|
||||
Reference in New Issue
Block a user