Add support for clouds config file
There is possibility to store credentials to various clouds in clouds config file which can be yaml or json format. This patch adds support for getting credentials from such file if OS_CLOUD env variable is set. Change-Id: Icd60cdd24ff6a74a5850c6434058384d1c4bddfe
This commit is contained in:
parent
b06ce3ae6f
commit
839a3117b6
|
@ -0,0 +1,44 @@
|
||||||
|
# Copyright 2019 Red Hat
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import appdirs
|
||||||
|
|
||||||
|
|
||||||
|
APPDIRS = appdirs.AppDirs('openstack', 'OpenStack', multipath='/etc')
|
||||||
|
CONFIG_HOME = APPDIRS.user_config_dir
|
||||||
|
CACHE_PATH = APPDIRS.user_cache_dir
|
||||||
|
|
||||||
|
UNIX_CONFIG_HOME = os.path.join(
|
||||||
|
os.path.expanduser(os.path.join('~', '.config')), 'openstack')
|
||||||
|
UNIX_SITE_CONFIG_HOME = '/etc/openstack'
|
||||||
|
|
||||||
|
SITE_CONFIG_HOME = APPDIRS.site_config_dir
|
||||||
|
|
||||||
|
CONFIG_SEARCH_PATH = [
|
||||||
|
os.getcwd(),
|
||||||
|
CONFIG_HOME, UNIX_CONFIG_HOME,
|
||||||
|
SITE_CONFIG_HOME, UNIX_SITE_CONFIG_HOME
|
||||||
|
]
|
||||||
|
YAML_SUFFIXES = ('.yaml', '.yml')
|
||||||
|
JSON_SUFFIXES = ('.json',)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cloud_config_files():
|
||||||
|
return [
|
||||||
|
os.path.join(d, 'clouds' + s)
|
||||||
|
for d in CONFIG_SEARCH_PATH
|
||||||
|
for s in YAML_SUFFIXES + JSON_SUFFIXES]
|
|
@ -14,6 +14,7 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ from oslo_log import log
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
import tobiko
|
import tobiko
|
||||||
|
from tobiko.openstack.keystone import _config_files
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
@ -223,6 +225,58 @@ class EnvironKeystoneCredentialsFixture(KeystoneCredentialsFixture):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class CloudsFileKeystoneCredentialsFixture(EnvironKeystoneCredentialsFixture):
|
||||||
|
|
||||||
|
def __init__(self, credentials=None, environ=None, clouds_files=None):
|
||||||
|
super(CloudsFileKeystoneCredentialsFixture, self).__init__(
|
||||||
|
credentials=credentials, environ=environ)
|
||||||
|
self.clouds_files = (
|
||||||
|
clouds_files or _config_files.get_cloud_config_files())
|
||||||
|
|
||||||
|
def _load_yaml_json_file(self, filelist):
|
||||||
|
for path in filelist:
|
||||||
|
if os.path.exists(path):
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
if path.endswith('json'):
|
||||||
|
return path, json.load(f)
|
||||||
|
else:
|
||||||
|
return path, yaml.safe_load(f)
|
||||||
|
return None, {}
|
||||||
|
|
||||||
|
def get_credentials(self):
|
||||||
|
cloud_name = self.get_env("OS_CLOUD")
|
||||||
|
if not cloud_name:
|
||||||
|
LOG.debug('No OS_CLOUD env variable')
|
||||||
|
return None
|
||||||
|
|
||||||
|
file_name, clouds_config = self._load_yaml_json_file(self.clouds_files)
|
||||||
|
|
||||||
|
clouds_config = clouds_config.get("clouds")
|
||||||
|
if not clouds_config:
|
||||||
|
LOG.debug('No clouds configs found in any of %s',
|
||||||
|
self.clouds_files)
|
||||||
|
return None
|
||||||
|
|
||||||
|
config = clouds_config.get(cloud_name)
|
||||||
|
if not config:
|
||||||
|
LOG.debug("No %s cloud config found in cloud configs file %s",
|
||||||
|
cloud_name, file_name)
|
||||||
|
return None
|
||||||
|
|
||||||
|
auth = config.get("auth", {})
|
||||||
|
return keystone_credentials(
|
||||||
|
api_version=int(config.get("identity_api_version")),
|
||||||
|
auth_url=auth.get("auth_url"),
|
||||||
|
username=auth.get("username"),
|
||||||
|
password=auth.get("password"),
|
||||||
|
project_name=auth.get("project_name"),
|
||||||
|
domain_name=auth.get("domain_name"),
|
||||||
|
user_domain_name=auth.get("user_domain_name"),
|
||||||
|
project_domain_name=auth.get("project_domain_name"),
|
||||||
|
project_domain_id=auth.get("project_domain_id"),
|
||||||
|
trust_id=auth.get("trust_id"))
|
||||||
|
|
||||||
|
|
||||||
class ConfigKeystoneCredentialsFixture(KeystoneCredentialsFixture):
|
class ConfigKeystoneCredentialsFixture(KeystoneCredentialsFixture):
|
||||||
|
|
||||||
def get_credentials(self):
|
def get_credentials(self):
|
||||||
|
@ -258,6 +312,7 @@ class ConfigKeystoneCredentialsFixture(KeystoneCredentialsFixture):
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_KEYSTONE_CREDENTIALS_FIXTURES = [
|
DEFAULT_KEYSTONE_CREDENTIALS_FIXTURES = [
|
||||||
|
CloudsFileKeystoneCredentialsFixture,
|
||||||
EnvironKeystoneCredentialsFixture,
|
EnvironKeystoneCredentialsFixture,
|
||||||
ConfigKeystoneCredentialsFixture]
|
ConfigKeystoneCredentialsFixture]
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,12 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import yaml
|
||||||
|
|
||||||
import tobiko
|
import tobiko
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
from tobiko.openstack import keystone
|
from tobiko.openstack import keystone
|
||||||
|
@ -61,6 +65,17 @@ V3_ENVIRON = {
|
||||||
'OS_USER_DOMAIN_NAME': 'Default',
|
'OS_USER_DOMAIN_NAME': 'Default',
|
||||||
'OS_PROJECT_DOMAIN_NAME': 'Default'}
|
'OS_PROJECT_DOMAIN_NAME': 'Default'}
|
||||||
|
|
||||||
|
CLOUDS_CONFIG = {
|
||||||
|
'clouds': {
|
||||||
|
'test-cloud': {
|
||||||
|
'auth': {'auth_url': V3_PARAMS['auth_url'],
|
||||||
|
'password': V3_PARAMS['password'],
|
||||||
|
'project_domain_name': V3_PARAMS['project_domain_name'],
|
||||||
|
'project_name': V3_PARAMS['project_name'],
|
||||||
|
'user_domain_name': V3_PARAMS['user_domain_name'],
|
||||||
|
'username': V3_PARAMS['username']},
|
||||||
|
'identity_api_version': str(V3_PARAMS['api_version'])}}}
|
||||||
|
|
||||||
V3_ENVIRON_WITH_VERSION = dict(V3_ENVIRON, OS_IDENTITY_API_VERSION='3')
|
V3_ENVIRON_WITH_VERSION = dict(V3_ENVIRON, OS_IDENTITY_API_VERSION='3')
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,6 +178,56 @@ class EnvironKeystoneCredentialsFixtureTest(openstack.OpenstackTest):
|
||||||
self.assertEqual(V3_PARAMS, fixture.credentials.to_dict())
|
self.assertEqual(V3_PARAMS, fixture.credentials.to_dict())
|
||||||
|
|
||||||
|
|
||||||
|
class CloudsFileKeystoneCredentialsFixtureTestJson(openstack.OpenstackTest):
|
||||||
|
|
||||||
|
clouds_file_name = "/tmp/test-cloud-file.json"
|
||||||
|
json_cloud_data = json.dumps(CLOUDS_CONFIG)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(CloudsFileKeystoneCredentialsFixtureTestJson, self).setUp()
|
||||||
|
self.patch(os, 'environ', {'OS_CLOUD': 'test-cloud'})
|
||||||
|
self.patch(os.path, 'exists', return_value=True)
|
||||||
|
mocked_open = mock.mock_open(read_data=self.json_cloud_data)
|
||||||
|
self.patch(_credentials, "open", mocked_open)
|
||||||
|
|
||||||
|
def test_setup_from_clouds_config_file(self):
|
||||||
|
fixture = _credentials.CloudsFileKeystoneCredentialsFixture(
|
||||||
|
clouds_files=[self.clouds_file_name])
|
||||||
|
fixture.setUp()
|
||||||
|
fixture.credentials.validate()
|
||||||
|
self.assertEqual(
|
||||||
|
V3_PARAMS, fixture.credentials.to_dict())
|
||||||
|
|
||||||
|
def test_setup_from_file_no_os_cloud_env_set(self):
|
||||||
|
self.patch(os, 'environ', {})
|
||||||
|
fixture = _credentials.CloudsFileKeystoneCredentialsFixture(
|
||||||
|
clouds_files=[self.clouds_file_name])
|
||||||
|
fixture.setUp()
|
||||||
|
self.assertIsNone(fixture.credentials)
|
||||||
|
|
||||||
|
def test_setup_from_file_no_clouds_config_in_file(self):
|
||||||
|
mocked_open = mock.mock_open(read_data=json.dumps({}))
|
||||||
|
self.patch(_credentials, "open", mocked_open)
|
||||||
|
fixture = _credentials.CloudsFileKeystoneCredentialsFixture(
|
||||||
|
clouds_files=[self.clouds_file_name])
|
||||||
|
fixture.setUp()
|
||||||
|
self.assertIsNone(fixture.credentials)
|
||||||
|
|
||||||
|
def test_setup_from_file_no_specified_cloud_config_in_file(self):
|
||||||
|
self.patch(os, 'environ', {'OS_CLOUD': 'some-other-cloud'})
|
||||||
|
fixture = _credentials.CloudsFileKeystoneCredentialsFixture(
|
||||||
|
clouds_files=[self.clouds_file_name])
|
||||||
|
fixture.setUp()
|
||||||
|
self.assertIsNone(fixture.credentials)
|
||||||
|
|
||||||
|
|
||||||
|
class CloudsFileKeystoneCredentialsFixtureTestYaml(
|
||||||
|
CloudsFileKeystoneCredentialsFixtureTestJson):
|
||||||
|
|
||||||
|
clouds_file_name = "/tmp/test-cloud-file.yaml"
|
||||||
|
json_cloud_data = yaml.dump(CLOUDS_CONFIG)
|
||||||
|
|
||||||
|
|
||||||
class ConfigKeystoneCredentialsFixtureTest(openstack.OpenstackTest):
|
class ConfigKeystoneCredentialsFixtureTest(openstack.OpenstackTest):
|
||||||
|
|
||||||
def patch_config(self, params, **kwargs):
|
def patch_config(self, params, **kwargs):
|
||||||
|
|
Loading…
Reference in New Issue