Skip to content

Commit

Permalink
Merge b7df810 into 3ebac9a
Browse files Browse the repository at this point in the history
  • Loading branch information
kdelee committed Feb 1, 2018
2 parents 3ebac9a + b7df810 commit be65dc5
Show file tree
Hide file tree
Showing 17 changed files with 395 additions and 38 deletions.
12 changes: 12 additions & 0 deletions camayoc/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,18 @@
QCS_HOST_MANAGER_TYPES = ('vcenter', 'satellite')
"""Types of host managers that the quipucords server supports."""

QCS_BECOME_METHODS = (
'doas',
'dzdo',
'ksu',
'pbrun',
'pfexec',
'runas',
'su',
'sudo',
)
"""Supported become methods for quipucords server."""

VCENTER_SCAN_TIMEOUT = 540
"""Maximum amount of time to let vcenter scan run before timing out."""

Expand Down
82 changes: 63 additions & 19 deletions camayoc/qcs_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"""Models for use with the Quipucords API."""

import re
import uuid

from pprint import pformat
from urllib.parse import urljoin

from camayoc import api
from camayoc.utils import uuid4
from camayoc.constants import MASKED_PASSWORD_OUTPUT
from camayoc.constants import (
QCS_CREDENTIALS_PATH,
Expand Down Expand Up @@ -180,8 +180,10 @@ def __init__(
username=None,
password=None,
ssh_keyfile=None,
sudo_password=None,
cred_type=None,
become_method=None,
become_password=None,
become_user=None,
_id=None):
"""Create a host credential with given data.
Expand All @@ -192,13 +194,18 @@ def __init__(
a password XOR a ssh_keyfile must be provided.
"""
super().__init__(client=client, _id=_id)
self.name = str(uuid.uuid4()) if name is None else name
self.name = uuid4() if name is None else name
self.endpoint = QCS_CREDENTIALS_PATH
self.username = str(uuid.uuid4()) if username is None else username
self.username = uuid4() if username is None else username
self.password = password
self.ssh_keyfile = ssh_keyfile
self.sudo_password = sudo_password
self.cred_type = cred_type
if become_method is not None:
self.become_method = become_method
if become_password is not None:
self.become_password = become_password
if become_user is not None:
self.become_user = become_user

def equivalent(self, other):
"""Return true if both objects are equal.
Expand All @@ -219,12 +226,26 @@ def equivalent(self, other):
)

password_matcher = re.compile(MASKED_PASSWORD_OUTPUT)
for key, value in self.fields().items():
if key == 'password' and other.get(key) is not None:
local_items = self.fields()
local_keys = local_items.keys()
other_keys = other.keys()
all_keys = set(local_keys).union(other_keys)
for key in all_keys:
if key not in [
'password',
'become_method',
'become_user',
'become_password']:
if not local_items.get(key) == other.get(key):
return False
if 'password' in key and local_items.get(key) is not None:
if not password_matcher.match(other.get(key)):
return False
else:
if not other.get(key) == value:
if key == 'become_method':
if not other.get(key) == local_items.get(key, 'sudo'):
return False
if key == 'become_user':
if not other.get(key) == local_items.get(key, 'root'):
return False
return True

Expand Down Expand Up @@ -266,7 +287,7 @@ def __init__(
A uuid4 name and api.Client are also supplied if none are provided.
"""
super().__init__(client=client, _id=_id)
self.name = str(uuid.uuid4()) if name is None else name
self.name = uuid4() if name is None else name
self.endpoint = QCS_SOURCE_PATH
self.hosts = hosts
if port is not None:
Expand Down Expand Up @@ -295,7 +316,23 @@ def equivalent(self, other):
'Sources objects or dictionaries.'
)

for key, value in self.fields().items():
local_items = self.fields()
local_keys = local_items.keys()
other_keys = other.keys()
all_keys = set(local_keys).union(other_keys)
for key in all_keys:
if key == 'port':
default_port = 22 if self.source_type == 'network' else 443
if int(
other.get(key)) != int(
local_items.get(
key,
default_port)):
return False
if key == 'options':
if self.source_type == 'satellite':
if other.get(key).get('satellite_version') != '6.2':
return False
if key == 'credentials':
other_creds = other.get('credentials')
cred_ids = []
Expand All @@ -305,10 +342,11 @@ def equivalent(self, other):
# the list of id's we used to create the source
for cred in other_creds:
cred_ids.append(cred.get('id'))
if sorted(value) != sorted(cred_ids):
if sorted(local_items.get(key)) != sorted(cred_ids):
return False
else:
if not other.get(key) == value:

if key not in ['port', 'credentials', 'options']:
if not other.get(key) == local_items.get(key):
return False
return True

Expand Down Expand Up @@ -437,11 +475,17 @@ def equivalent(self, other):
'Scan objects or dictionaries.'
)

for key, value in self.fields().items():
if key == 'source':
if value != other.get(key).get('id'):
local_items = self.fields()
local_keys = local_items.keys()
other_keys = other.keys()
all_keys = set(local_keys).union(other_keys)
for key in all_keys:
if key == 'status':
continue
if key == 'sources':
if sorted(local_items[key]) != sorted(other[key]):
return False
else:
if not other.get(key) == value:
if key not in ['status', 'sources']:
if not other[key] == local_items[key]:
return False
return True
2 changes: 1 addition & 1 deletion camayoc/tests/qcs/api/v1/credentials/test_creds_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
def test_create_with_password(cred_type, shared_client, cleanup):
"""Create a credential with username and password.
:id: d04e3e1b-c7f1-4cc2-a4a4-a3d3317f95ce
:id: bcc6a15f-a5b5-4939-9602-e5bccf4a75ca
:description: Create a credential with a user name and password
:steps: Send POST with necessary data to documented api endpoint.
:expectedresults: A new credential entry is created with the data.
Expand Down
47 changes: 47 additions & 0 deletions camayoc/tests/qcs/api/v1/credentials/test_manager_creds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# coding=utf-8
"""Tests for the ``Credential`` API endpoint.
:caseautomation: automated
:casecomponent: api
:caseimportance: high
:caselevel: integration
:requirement: Sonar
:testtype: functional
:upstream: yes
"""
import requests

import pytest

from camayoc.constants import (
QCS_HOST_MANAGER_TYPES,
QCS_BECOME_METHODS,
)
from camayoc.qcs_models import Credential
from camayoc.utils import uuid4


@pytest.mark.parametrize('method', QCS_BECOME_METHODS)
@pytest.mark.parametrize('cred_type', QCS_HOST_MANAGER_TYPES)
def test_negative_create_with_become(
cred_type, shared_client, cleanup, method):
"""Attempt to pass 'become' options to host manager credentials.
:id: d04e3e1b-c7f1-4cc2-a4a4-a3d3317f95ce
:description: Attempt to pass 'become' options that are only valid for
network credentials to create host manager credentials.
:steps: Attempt to create a host manager credential sending valid data
along with the extra invalid become options.
:expectedresults: An error is thrown and no new credential is created.
"""
cred = Credential(
cred_type=cred_type,
client=shared_client,
password=uuid4(),
become_method=method,
become_password=uuid4(),
become_user=uuid4(),
)
with pytest.raises(requests.HTTPError):
cred.create()
cleanup.append(cred)
55 changes: 48 additions & 7 deletions camayoc/tests/qcs/api/v1/credentials/test_network_creds.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
:testtype: functional
:upstream: yes
"""
import requests

from pathlib import Path

import pytest

from camayoc import api
from camayoc.constants import QCS_BECOME_METHODS
from camayoc.qcs_models import Credential
from camayoc.utils import uuid4
from camayoc.tests.qcs.utils import assert_matches_server
Expand Down Expand Up @@ -180,15 +183,53 @@ def test_negative_create_key_and_pass(cleanup, isolated_filesystem):
assert cred._id is None


@pytest.mark.skip
def test_create_sudo_password(cleanup, isolated_filesystem):
"""Create a network credential that has a sudo password.
@pytest.mark.parametrize('method', QCS_BECOME_METHODS)
def test_create_become_method(cleanup, shared_client, method):
"""Create a network credential that uses become options.
:id: e49e497d-abb7-4d6a-8366-3409e297062a
:description: Create a network credential with username, password XOR
sshkey, and a sudo password.
:description: Create a network credential with username, password
and uses a become method.
:steps: Send a POST to the credential endpoint with data.
:expectedresults: A new network credential is created.
:caseautomation: notautomated
"""
pass
cred = Credential(
cred_type='network',
client=shared_client,
password=uuid4(),
become_method=method,
become_password=uuid4(),
become_user=uuid4(),
)
cred.create()
# add the id to the list to destroy after the test is done
cleanup.append(cred)
assert_matches_server(cred)


@pytest.mark.parametrize('invalid_method', ['not-a-method', 86])
def test_negative_invalid_become_method(cleanup,
shared_client,
invalid_method
):
"""Attempt to create a network credential with unsupported become options.
:id: f05f2ea8-ae9f-4bad-a76f-5246128400d9
:description: Submit an otherwise well formed request to create a network
credential with a become method, but provide a become method that is
not supported.
:steps: Send a POST to the credential endpoint that is well formed except
contains a become method that the server does not know how to use.
:expectedresults: No new credential is created.
"""
cred = Credential(
cred_type='network',
client=shared_client,
password=uuid4(),
become_method=invalid_method,
become_password=uuid4(),
become_user=uuid4(),
)
with pytest.raises(requests.HTTPError):
cred.create()
cleanup.append(cred)
48 changes: 48 additions & 0 deletions camayoc/tests/qcs/api/v1/scans/test_multi_source_scans.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# coding=utf-8
"""Tests for ``Scan`` API endpoint for quipucords server.
:caseautomation: automated
:casecomponent: api
:caseimportance: high
:caselevel: integration
:requirement: Sonar
:testtype: functional
:upstream: yes
"""

import pytest

from camayoc.tests.qcs.api.v1.utils import (
prep_all_source_scan,
wait_until_state,
)


@pytest.mark.parametrize('scan_type', ['connect', 'inspect'])
def test_multi_source_create(shared_client, cleanup, scan_type):
"""Run a scan on a collection of sources and confirm it completes.
:id: 43624cc1-6c41-4c2d-9919-c3d0aae83165
:description: Create sources for each source specified in the
config file and then create a scan that scans all the sources.
Provided that the resources are specified in the config file, this
will test that scans including multiple sources of mixed types can
be created and complete.
:steps:
1) Create all credentials specified in config file
2) Create all sources specified in config file, using appropriate
credentials
3) Create a scan using all sources
4) Assert that the scan completes and a fact id is generated
:expectedresults: A scan is run and has facts associated with it
Also, scan results should be available during the scan.
"""
scan = prep_all_source_scan(cleanup, shared_client, scan_type)
scan.create()
if scan_type == 'inspect':
wait_until_state(scan, state='running')
assert 'connection_results' in scan.results().json().keys()
assert 'inspection_results' in scan.results().json().keys()
wait_until_state(scan, state='completed', timeout=600)
if scan_type == 'inspect':
assert scan.read().json().get('fact_collection_id') > 0
Loading

0 comments on commit be65dc5

Please sign in to comment.