Prepare acceptance tests for real clouds
- reworked job not to use custom modules, but rather send direct API requests (due to mess with ensuring openstacksdk availability for Ansible). - add exclude for pre-commit-config to stop it from complaining on zuul.yaml - removed too verbose logging from functests with list of images and flavors (on real clouds this is simply too much). Change-Id: I555127f410b696e1584dc07cafac25597ab1abeb
This commit is contained in:
parent
4ae03c0ab4
commit
50711b4662
@ -16,6 +16,7 @@ repos:
|
||||
- id: debug-statements
|
||||
- id: check-yaml
|
||||
files: .*\.(yaml|yml)$
|
||||
exclude: '^.zuul.yaml'
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: flake8
|
||||
|
61
.zuul.yaml
61
.zuul.yaml
@ -439,16 +439,43 @@
|
||||
- job:
|
||||
name: openstacksdk-acceptance-base
|
||||
parent: openstack-tox
|
||||
description: Acceptance test of the OpenStackSDK on real clouds
|
||||
description: |
|
||||
Acceptance test of the OpenStackSDK on real clouds.
|
||||
|
||||
.. zuul:jobsvar::openstack_credentials
|
||||
:type: dict
|
||||
|
||||
This is expected to be a Zuul Secret with these keys:
|
||||
|
||||
.. zuul:jobvar: auth
|
||||
:type: dict
|
||||
|
||||
Dictionary with authentication information with mandatory auth_url
|
||||
and others. The structure mimics `clouds.yaml` structure.
|
||||
|
||||
By default all jobs that inherit from here are non voting.
|
||||
|
||||
attempts: 1
|
||||
voting: false
|
||||
pre-run:
|
||||
- playbooks/acceptance/pre.yaml
|
||||
post-run:
|
||||
- playbooks/acceptance/post.yaml
|
||||
vars:
|
||||
tox_envlist: acceptance-regular-user
|
||||
tox_environment:
|
||||
OPENSTACKSDK_DEMO_CLOUD: acceptance
|
||||
OS_CLOUD: acceptance
|
||||
OS_TEST_CLOUD: acceptance
|
||||
|
||||
# Acceptance tests for devstack are different from running for real cloud since
|
||||
# we need to actually deploy devstack first and API is available only on the
|
||||
# devstack host.
|
||||
- job:
|
||||
name: openstacksdk-acceptance-devstack
|
||||
parent: openstacksdk-functional-devstack
|
||||
description: Acceptance test of the OpenStackSDK on real clouds
|
||||
description: Acceptance test of the OpenStackSDK on real clouds.
|
||||
attempts: 1
|
||||
run:
|
||||
- playbooks/acceptance/run-with-devstack.yaml
|
||||
post-run:
|
||||
@ -459,17 +486,25 @@
|
||||
OPENSTACKSDK_DEMO_CLOUD: acceptance
|
||||
OS_CLOUD: acceptance
|
||||
OS_TEST_CLOUD: acceptance
|
||||
openstack_credentials:
|
||||
auth:
|
||||
auth_url: "https://{{ hostvars['controller']['nodepool']['private_ipv4'] }}/identity"
|
||||
username: demo
|
||||
password: secretadmin
|
||||
project_domain_id: default
|
||||
project_name: demo
|
||||
user_domain_id: default
|
||||
identity_api_version: '3'
|
||||
region_name: RegionOne
|
||||
volume_api_version: '3'
|
||||
auth_url: "https://{{ hostvars['controller']['nodepool']['private_ipv4'] }}/identity"
|
||||
secrets:
|
||||
- secret: credentials-devstack
|
||||
name: openstack_credentials
|
||||
|
||||
# Devstack secret is not specifying auth_url because of how Zuul treats secrets.
|
||||
# Auth_url comes extra in the job vars and is being used if no auth_url in the
|
||||
# secret is present.
|
||||
- secret:
|
||||
name: credentials-devstack
|
||||
data:
|
||||
auth:
|
||||
username: demo
|
||||
password: secretadmin
|
||||
project_domain_id: default
|
||||
project_name: demo
|
||||
user_domain_id: default
|
||||
region_name: RegionOne
|
||||
verify: false
|
||||
|
||||
- project-template:
|
||||
name: openstacksdk-functional-tips
|
||||
|
@ -106,7 +106,7 @@ class BaseFunctionalTest(base.TestCase):
|
||||
return None
|
||||
|
||||
flavors = self.user_cloud.list_flavors(get_extra=False)
|
||||
self.add_info_on_exception('flavors', flavors)
|
||||
# self.add_info_on_exception('flavors', flavors)
|
||||
|
||||
flavor_name = os.environ.get('OPENSTACKSDK_FLAVOR')
|
||||
|
||||
@ -146,7 +146,7 @@ class BaseFunctionalTest(base.TestCase):
|
||||
return None
|
||||
|
||||
images = self.user_cloud.list_images()
|
||||
self.add_info_on_exception('images', images)
|
||||
# self.add_info_on_exception('images', images)
|
||||
|
||||
image_name = os.environ.get('OPENSTACKSDK_IMAGE')
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
../library
|
@ -1,18 +1,42 @@
|
||||
- hosts: localhost
|
||||
---
|
||||
# This could be running on localhost only, but then the devstack job would need
|
||||
# to perform API call on the worker node. To keep the code a bit less crazy
|
||||
# rather address all hosts and perform certain steps on the localhost (zuul
|
||||
# executor).
|
||||
- hosts: all
|
||||
tasks:
|
||||
# TODO:
|
||||
# - clean the resources, which might have been created
|
||||
# - revoke the temp token explicitly
|
||||
- name: read token
|
||||
command: "cat {{ zuul.executor.work_root }}/.{{ zuul.build }}"
|
||||
register: token_data
|
||||
|
||||
# Token is saved on the zuul executor node
|
||||
- name: Check token file
|
||||
delegate_to: localhost
|
||||
ansible.builtin.stat:
|
||||
path: "{{ zuul.executor.work_root }}/.{{ zuul.build }}"
|
||||
register: token_file
|
||||
|
||||
# no_log is important since content WILL in logs
|
||||
- name: Read the token from file
|
||||
delegate_to: localhost
|
||||
no_log: true
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ token_file.stat.path }}"
|
||||
register: token_data
|
||||
when: "token_file.stat.exists"
|
||||
|
||||
- name: delete data file
|
||||
command: "shred {{ zuul.executor.work_root }}/.{{ zuul.build }}"
|
||||
- name: Delete data file
|
||||
delegate_to: localhost
|
||||
command: "shred {{ token_file.stat.path }}"
|
||||
when: "token_file.stat.exists"
|
||||
|
||||
- include_role:
|
||||
name: revoke_token
|
||||
vars:
|
||||
cloud: "{{ openstack_credentials }}"
|
||||
token: "{{ token_data.stdout }}"
|
||||
# no_log is important since content WILL appear in logs
|
||||
- name: Revoke token
|
||||
no_log: true
|
||||
ansible.builtin.uri:
|
||||
url: "{{ openstack_credentials.auth.auth_url | default(auth_url) }}/v3/auth/tokens"
|
||||
method: "DELETE"
|
||||
headers:
|
||||
X-Auth-Token: "{{ token_data['content'] | b64decode }}"
|
||||
X-Subject-Token: "{{ token_data['content'] | b64decode }}"
|
||||
status_code: 204
|
||||
when: "token_file.stat.exists and 'content' in token_data"
|
||||
|
@ -1,40 +1,45 @@
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: Get temporary token for the cloud
|
||||
# nolog is important to keep job-output.json clean
|
||||
# nolog is important since content WILL appear in logs
|
||||
no_log: true
|
||||
os_auth:
|
||||
cloud:
|
||||
profile: "{{ openstack_credentials.profile | default(omit) }}"
|
||||
ansible.builtin.uri:
|
||||
url: "{{ openstack_credentials.auth.auth_url | default(auth_url) }}/v3/auth/tokens"
|
||||
method: "POST"
|
||||
body_format: "json"
|
||||
body:
|
||||
auth:
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url }}"
|
||||
username: "{{ openstack_credentials.auth.username }}"
|
||||
password: "{{ openstack_credentials.auth.password }}"
|
||||
user_domain_name: "{{ openstack_credentials.auth.user_domain_name | default(omit) }}"
|
||||
user_domain_id: "{{ openstack_credentials.auth.user_domain_id | default(omit) }}"
|
||||
domain_name: "{{ openstack_credentials.auth.domain_name | default(omit) }}"
|
||||
domain_id: "{{ openstack_credentials.auth.domain_id | default(omit) }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
project_id: "{{ openstack_credentials.auth.project_id | default(omit) }}"
|
||||
project_domain_name: "{{ openstack_credentials.auth.project_domain_name | default(omit) }}"
|
||||
project_domain_id: "{{ openstack_credentials.auth.project_domain_id | default(omit) }}"
|
||||
identity:
|
||||
methods: ["password"]
|
||||
password:
|
||||
user:
|
||||
name: "{{ openstack_credentials.auth.username | default(omit) }}"
|
||||
id: "{{ openstack_credentials.auth.user_id | default(omit) }}"
|
||||
password: "{{ openstack_credentials.auth.password }}"
|
||||
domain:
|
||||
name: "{{ openstack_credentials.auth.user_domain_name | default(omit) }}"
|
||||
id: "{{ openstack_credentials.auth.user_domain_id | default(omit) }}"
|
||||
scope:
|
||||
project:
|
||||
name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
id: "{{ openstack_credentials.auth.project_id | default(omit) }}"
|
||||
domain:
|
||||
name: "{{ openstack_credentials.auth.project_domain_name | default(omit) }}"
|
||||
id: "{{ openstack_credentials.auth.project_domain_id | default(omit) }}"
|
||||
return_content: true
|
||||
status_code: 201
|
||||
register: os_auth
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Verify token
|
||||
# nolog is important since content WILL appear in logs
|
||||
no_log: true
|
||||
os_auth:
|
||||
cloud:
|
||||
profile: "{{ openstack_credentials.profile | default(omit) }}"
|
||||
auth_type: token
|
||||
auth:
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url }}"
|
||||
token: "{{ os_auth.auth_token }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
project_id: "{{ openstack_credentials.auth.project_id | default(omit) }}"
|
||||
project_domain_id: "{{ openstack_credentials.auth.project_domain_id | default(omit) }}"
|
||||
project_domain_name: "{{ openstack_credentials.auth.project_domain_name | default(omit) }}"
|
||||
delegate_to: localhost
|
||||
ansible.builtin.uri:
|
||||
url: "{{ openstack_credentials.auth.auth_url | default(auth_url) }}/v3/auth/tokens"
|
||||
method: "GET"
|
||||
headers:
|
||||
X-Auth-Token: "{{ os_auth.x_subject_token }}"
|
||||
X-Subject-Token: "{{ os_auth.x_subject_token }}"
|
||||
|
||||
- name: Include deploy-clouds-config role
|
||||
include_role:
|
||||
@ -43,18 +48,22 @@
|
||||
cloud_config:
|
||||
clouds:
|
||||
acceptance:
|
||||
profile: "{{ openstack_credentials.profile | default(omit) }}"
|
||||
profile: "{{ openstack_credentials.profile | default('') }}"
|
||||
auth_type: "token"
|
||||
auth:
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url | default(omit) }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
token: "{{ os_auth.auth_token }}"
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url | default(auth_url) }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default('') }}"
|
||||
project_domain_id: "{{ openstack_credentials.auth.project_domain_id | default('') }}"
|
||||
project_domain_name: "{{ openstack_credentials.auth.project_domain_name | default('') }}"
|
||||
token: "{{ os_auth.x_subject_token }}"
|
||||
region_name: "{{ openstack_credentials.region_name | default('') }}"
|
||||
verify: "{{ openstack_credentials.verify | default(true) }}"
|
||||
|
||||
# Intruders might want to corrupt clouds.yaml to avoid revoking token in the post phase
|
||||
# To prevent this we save token on the executor for later use.
|
||||
- name: Save token
|
||||
- name: Save the token
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
dest: "{{ zuul.executor.work_root }}/.{{ zuul.build }}"
|
||||
content: "{{ os_auth.auth_token }}"
|
||||
mode: "0440"
|
||||
content: "{{ os_auth.x_subject_token }}"
|
||||
mode: "0640"
|
||||
|
@ -1,75 +1,11 @@
|
||||
---
|
||||
# Need to actually start devstack first
|
||||
- hosts: all
|
||||
roles:
|
||||
- run-devstack
|
||||
|
||||
# Prepare local clouds.yaml
|
||||
# We can't rely on pre.yaml, since it is specifically delegates to
|
||||
# localhost, while on devstack it will not work unless APIs are available
|
||||
# over the net.
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: Get temporary token for the cloud
|
||||
# nolog is important to keep job-output.json clean
|
||||
no_log: true
|
||||
os_auth:
|
||||
cloud:
|
||||
profile: "{{ openstack_credentials.profile | default(omit) }}"
|
||||
auth:
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url }}"
|
||||
username: "{{ openstack_credentials.auth.username }}"
|
||||
password: "{{ openstack_credentials.auth.password }}"
|
||||
user_domain_name: "{{ openstack_credentials.auth.user_domain_name | default(omit) }}"
|
||||
user_domain_id: "{{ openstack_credentials.auth.user_domain_id | default(omit) }}"
|
||||
domain_name: "{{ openstack_credentials.auth.domain_name | default(omit) }}"
|
||||
domain_id: "{{ openstack_credentials.auth.domain_id | default(omit) }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
project_id: "{{ openstack_credentials.auth.project_id | default(omit) }}"
|
||||
project_domain_name: "{{ openstack_credentials.auth.project_domain_name | default(omit) }}"
|
||||
project_domain_id: "{{ openstack_credentials.auth.project_domain_id | default(omit) }}"
|
||||
register: os_auth
|
||||
|
||||
- name: Verify token
|
||||
# nolog is important to keep job-output.json clean
|
||||
no_log: true
|
||||
os_auth:
|
||||
cloud:
|
||||
profile: "{{ openstack_credentials.profile | default(omit) }}"
|
||||
auth_type: token
|
||||
auth:
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url }}"
|
||||
token: "{{ os_auth.auth_token }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
project_id: "{{ openstack_credentials.auth.project_id | default(omit) }}"
|
||||
project_domain_name: "{{ openstack_credentials.auth.project_domain_name | default(omit) }}"
|
||||
project_domain_id: "{{ openstack_credentials.auth.project_domain_id | default(omit) }}"
|
||||
|
||||
- name: Include deploy-clouds-config role
|
||||
include_role:
|
||||
name: deploy-clouds-config
|
||||
vars:
|
||||
cloud_config:
|
||||
clouds:
|
||||
acceptance:
|
||||
profile: "{{ openstack_credentials.profile | default(omit) }}"
|
||||
auth_type: "token"
|
||||
auth:
|
||||
|
||||
auth_url: "{{ openstack_credentials.auth.auth_url }}"
|
||||
project_name: "{{ openstack_credentials.auth.project_name | default(omit) }}"
|
||||
project_domain_id: "{{ openstack_credentials.auth.project_domain_id | default(omit) }}"
|
||||
token: "{{ os_auth.auth_token }}"
|
||||
verify: false
|
||||
|
||||
# Intruders might want to corrupt clouds.yaml to avoid revoking token in
|
||||
# the post phase. To prevent this we save token on the executor for later
|
||||
# use.
|
||||
- name: Save token
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
dest: "{{ zuul.executor.work_root }}/.{{ zuul.build }}"
|
||||
content: "{{ os_auth.auth_token }}"
|
||||
mode: "0640"
|
||||
- name: Get the token
|
||||
ansible.builtin.import_playbook: pre.yaml
|
||||
|
||||
# Run the rest
|
||||
- hosts: all
|
||||
|
@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Utility to get Keystone token
|
||||
"""
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
import openstack
|
||||
|
||||
|
||||
def get_cloud(cloud):
|
||||
if isinstance(cloud, dict):
|
||||
config = openstack.config.loader.OpenStackConfig().get_one(**cloud)
|
||||
return openstack.connection.Connection(config=config)
|
||||
else:
|
||||
return openstack.connect(cloud=cloud)
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
cloud=dict(required=True, type='raw', no_log=True),
|
||||
)
|
||||
)
|
||||
cloud = get_cloud(module.params.get('cloud'))
|
||||
module.exit_json(
|
||||
changed=True,
|
||||
auth_token=cloud.auth_token
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2014 Rackspace Australia
|
||||
# Copyright 2018 Red Hat, Inc
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Utility to revoke Keystone token
|
||||
"""
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import keystoneauth1.exceptions
|
||||
import requests
|
||||
import requests.exceptions
|
||||
|
||||
import openstack
|
||||
|
||||
|
||||
def get_cloud(cloud):
|
||||
if isinstance(cloud, dict):
|
||||
config = openstack.config.loader.OpenStackConfig().get_one(**cloud)
|
||||
return openstack.connection.Connection(config=config)
|
||||
else:
|
||||
return openstack.connect(cloud=cloud)
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
cloud=dict(required=True, type='raw', no_log=True),
|
||||
revoke_token=dict(required=True, type='str', no_log=True)
|
||||
)
|
||||
)
|
||||
|
||||
p = module.params
|
||||
cloud = get_cloud(p.get('cloud'))
|
||||
try:
|
||||
cloud.identity.delete(
|
||||
'/auth/tokens',
|
||||
headers={
|
||||
'X-Subject-Token': p.get('revoke_token')
|
||||
}
|
||||
)
|
||||
except (keystoneauth1.exceptions.http.HttpError,
|
||||
requests.exceptions.RequestException):
|
||||
s = "Error performing token revoke"
|
||||
logging.exception(s)
|
||||
s += "\n" + traceback.format_exc()
|
||||
module.fail_json(
|
||||
changed=False,
|
||||
msg=s,
|
||||
cloud=cloud.name,
|
||||
region_name=cloud.config.region_name)
|
||||
module.exit_json(changed=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,7 +0,0 @@
|
||||
- name: Revoke token
|
||||
delegate_to: localhost
|
||||
no_log: true
|
||||
os_auth_revoke:
|
||||
cloud: "{{ cloud }}"
|
||||
revoke_token: "{{ token }}"
|
||||
failed_when: false
|
Loading…
Reference in New Issue
Block a user