Skip to content

Commit

Permalink
Merge pull request #949 from dachary/wip-openstack-token-endpoint
Browse files Browse the repository at this point in the history
openstack: use OS_AUTH_TYPE=token_endpoint when possible

Reviewed-by: Dan Mick <dmick@redhat.com>
  • Loading branch information
dmick committed Sep 23, 2016
2 parents 6fac32f + 082f4c1 commit 04a68d8
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 42 deletions.
63 changes: 52 additions & 11 deletions teuthology/openstack/__init__.py
Expand Up @@ -215,31 +215,66 @@ def cache_token(self):
if self.provider != 'ovh':
return False
if (OpenStack.token is None and
os.environ.get('OS_AUTH_TYPE') == 'v2token' and
'OS_TOKEN' in os.environ and
'OS_TOKEN_VALUE' in os.environ and
'OS_TOKEN_EXPIRES' in os.environ):
log.debug("get token from the environment of the parent process")
OpenStack.token = os.environ['OS_TOKEN']
OpenStack.token = os.environ['OS_TOKEN_VALUE']
OpenStack.token_expires = int(os.environ['OS_TOKEN_EXPIRES'])
if (OpenStack.token_expires is not None and
OpenStack.token_expires < time.time()):
log.debug("token discarded because it has expired")
OpenStack.token = None
if OpenStack.token is None:
if os.environ.get('OS_AUTH_TYPE') == 'v2token':
del os.environ['OS_AUTH_TYPE']
if 'OS_TOKEN_VALUE' in os.environ:
del os.environ['OS_TOKEN_VALUE']
OpenStack.token = misc.sh("openstack -q token issue -c id -f value").strip()
os.environ['OS_AUTH_TYPE'] = 'v2token'
os.environ['OS_TOKEN'] = OpenStack.token
os.environ['OS_TOKEN_VALUE'] = OpenStack.token
OpenStack.token_expires = int(time.time() + OpenStack.token_cache_duration)
os.environ['OS_TOKEN_EXPIRES'] = str(OpenStack.token_expires)
log.info("caching OS_TOKEN and setting OS_AUTH_TYPE=v2token "
log.info("caching OS_TOKEN_VALUE "
"during %s seconds" % OpenStack.token_cache_duration)
return True

def get_os_url(self, cmd, type=None):
if self.provider != 'ovh':
return ""
url = ""
if (type == 'compute' or
cmd.startswith("server ") or
cmd.startswith("flavor ")):
url = "https://compute.{reg}.cloud.ovh.net/v2/{tenant}"
elif (type == 'network' or
cmd.startswith("ip ") or
cmd.startswith("security ") or
cmd.startswith("network ")):
url = "https://network.compute.{reg}.cloud.ovh.net/"
elif (type == 'image' or
cmd.startswith("image ")):
url = "https://image.compute.{reg}.cloud.ovh.net/"
elif (type == 'volume' or
cmd.startswith("volume ")):
url = "https://volume.compute.{reg}.cloud.ovh.net/v2/{tenant}"
if url != "":
url = url.format(reg=os.environ['OS_REGION_NAME'],
tenant=os.environ['OS_TENANT_ID'])
return url

def run(self, cmd, *args, **kwargs):
self.cache_token()
return misc.sh("openstack --quiet " + cmd, *args, **kwargs)
url = self.get_os_url(cmd, kwargs.get('type'))
if url != "":
if self.cache_token():
os.environ['OS_TOKEN'] = os.environ['OS_TOKEN_VALUE']
os.environ['OS_URL'] = url
if re.match('(server|flavor|ip|security|network|image|volume)', cmd):
cmd = "openstack --quiet " + cmd
try:
status = misc.sh(cmd)
finally:
if 'OS_TOKEN' in os.environ:
del os.environ['OS_TOKEN']
if 'OS_URL' in os.environ:
del os.environ['OS_URL']
return status

def set_provider(self):
if 'OS_AUTH_URL' not in os.environ:
Expand Down Expand Up @@ -681,6 +716,8 @@ def get_user_data(self):
template = open(user_data).read()
openrc = ''
for (var, value) in os.environ.iteritems():
if var in ('OS_TOKEN_VALUE', 'OS_TOKEN_EXPIRES'):
continue
if var.startswith('OS_'):
openrc += ' ' + var + '=' + value
if self.args.upload:
Expand Down Expand Up @@ -745,7 +782,11 @@ def get_unassociated_floating_ip():

@staticmethod
def create_floating_ip():
pools = json.loads(OpenStack().run("ip floating pool list -f json"))
try:
pools = json.loads(OpenStack().run("ip floating pool list -f json"))
except subprocess.CalledProcessError:
log.debug("create_floating_ip: ip floating pool list failed")
return None
if not pools:
return None
pool = pools[0]['Name']
Expand Down
51 changes: 34 additions & 17 deletions teuthology/openstack/test/test_openstack.py
@@ -1,5 +1,5 @@
#
# Copyright (c) 2015 Red Hat, Inc.
# Copyright (c) 2015,2016 Red Hat, Inc.
#
# Author: Loic Dachary <loic@dachary.org>
#
Expand Down Expand Up @@ -274,6 +274,31 @@ def test_get_provider(self):
else:
del os.environ['OS_AUTH_URL']

def test_get_os_url(self):
o = OpenStack()
#
# Only for OVH
#
o.provider = 'something'
assert "" == o.get_os_url("server ")
o.provider = 'ovh'
assert "" == o.get_os_url("unknown ")
type2cmd = {
'compute': ('server', 'flavor'),
'network': ('ip', 'security', 'network'),
'image': ('image',),
'volume': ('volume',),
}
os.environ['OS_REGION_NAME'] = 'REGION'
os.environ['OS_TENANT_ID'] = 'TENANT'
for (type, cmds) in type2cmd.iteritems():
for cmd in cmds:
assert ("//" + type) in o.get_os_url(cmd + " ")
for type in type2cmd.keys():
assert ("//" + type) in o.get_os_url("whatever ", type=type)
del os.environ['OS_REGION_NAME']
del os.environ['OS_TENANT_ID']

@patch('teuthology.misc.sh')
def test_cache_token(self, m_sh):
token = 'TOKEN VALUE'
Expand All @@ -289,13 +314,11 @@ def test_cache_token(self, m_sh):
#
# Set the environment with the token
#
assert 'OS_AUTH_TYPE' not in os.environ
assert 'OS_TOKEN' not in os.environ
assert 'OS_TOKEN_VALUE' not in os.environ
assert 'OS_TOKEN_EXPIRES' not in os.environ
assert True == o.cache_token()
m_sh.assert_called_with('openstack -q token issue -c id -f value')
assert 'v2token' == os.environ['OS_AUTH_TYPE']
assert token == os.environ['OS_TOKEN']
assert token == os.environ['OS_TOKEN_VALUE']
assert token == OpenStack.token
assert time.time() < int(os.environ['OS_TOKEN_EXPIRES'])
assert time.time() < OpenStack.token_expires
Expand All @@ -307,8 +330,7 @@ def test_cache_token(self, m_sh):
assert True == o.cache_token()
assert time.time() < int(os.environ['OS_TOKEN_EXPIRES'])
assert time.time() < OpenStack.token_expires
del os.environ['OS_AUTH_TYPE']
del os.environ['OS_TOKEN']
del os.environ['OS_TOKEN_VALUE']
del os.environ['OS_TOKEN_EXPIRES']

@patch('teuthology.misc.sh')
Expand All @@ -317,16 +339,14 @@ def test_cache_token_from_environment(self, m_sh):
o = OpenStack()
o.provider = 'ovh'
token = 'TOKEN VALUE'
os.environ['OS_AUTH_TYPE'] = 'v2token'
os.environ['OS_TOKEN'] = token
os.environ['OS_TOKEN_VALUE'] = token
token_expires = int(time.time()) + OpenStack.token_cache_duration
os.environ['OS_TOKEN_EXPIRES'] = str(token_expires)
assert True == o.cache_token()
assert token == OpenStack.token
assert token_expires == OpenStack.token_expires
m_sh.assert_not_called()
del os.environ['OS_AUTH_TYPE']
del os.environ['OS_TOKEN']
del os.environ['OS_TOKEN_VALUE']
del os.environ['OS_TOKEN_EXPIRES']

@patch('teuthology.misc.sh')
Expand All @@ -336,19 +356,16 @@ def test_cache_token_expired_environment(self, m_sh):
OpenStack.token = None
o = OpenStack()
o.provider = 'ovh'
os.environ['OS_AUTH_TYPE'] = 'v2token'
os.environ['OS_TOKEN'] = token
os.environ['OS_TOKEN_VALUE'] = token
token_expires = int(time.time()) - 2000
os.environ['OS_TOKEN_EXPIRES'] = str(token_expires)
assert True == o.cache_token()
m_sh.assert_called_with('openstack -q token issue -c id -f value')
assert 'v2token' == os.environ['OS_AUTH_TYPE']
assert token == os.environ['OS_TOKEN']
assert token == os.environ['OS_TOKEN_VALUE']
assert token == OpenStack.token
assert time.time() < int(os.environ['OS_TOKEN_EXPIRES'])
assert time.time() < OpenStack.token_expires
del os.environ['OS_AUTH_TYPE']
del os.environ['OS_TOKEN']
del os.environ['OS_TOKEN_VALUE']
del os.environ['OS_TOKEN_EXPIRES']

class TestTeuthologyOpenStack(object):
Expand Down
39 changes: 25 additions & 14 deletions teuthology/provision/openstack.py
Expand Up @@ -66,22 +66,33 @@ def attach_volumes(self, name, volumes):
except subprocess.CalledProcessError as e:
if 'No volume with a name or ID' not in e.output:
raise e
self.run("volume create -f json " +
config['openstack'].get('volume-create', '') + " " +
" --property ownedby=" + config.openstack['ip'] +
" --size " + str(volumes['size']) + " " +
volume_name)
# do not use OpenStack().run because its
# bugous for volume create as of openstackclient 3.2.0
# https://bugs.launchpad.net/python-openstackclient/+bug/1619726
misc.sh(
"openstack volume create -f json " +
config['openstack'].get('volume-create', '') + " " +
" --property ownedby=" + config.openstack['ip'] +
" --size " + str(volumes['size']) + " " +
volume_name)
with safe_while(sleep=2, tries=100,
action="volume " + volume_name) as proceed:
while proceed():
r = self.run("volume show -f json " + volume_name)
status = self.get_value(json.loads(r), 'status')
if status == 'available':
break
else:
log.info("volume " + volume_name +
" not available yet")
self.run("server add volume " + name + " " + volume_name)
try:
r = OpenStack().run("volume show -f json " +
volume_name)
status = self.get_value(json.loads(r), 'status')
if status == 'available':
break
else:
log.info("volume " + volume_name +
" not available yet")
except subprocess.CalledProcessError:
log.info("volume " + volume_name +
" not information available yet")
# do not use OpenStack().run because its
# bugous for volume
misc.sh("openstack server add volume " + name + " " + volume_name)

@staticmethod
def ip2name(prefix, ip):
Expand Down Expand Up @@ -127,7 +138,7 @@ def create(self, num, os_type, os_version, arch, resources_hint):
" --wait " +
" " + self.basename)
try:
misc.sh(cmd)
self.run(cmd, type='compute')
except CalledProcessError as exc:
if "quota exceeded" in exc.output.lower():
raise QuotaExceededError(message=exc.output)
Expand Down

0 comments on commit 04a68d8

Please sign in to comment.