def test_create(shared_client, cleanup, scan_host, src_type): """Create a Source using a single credential. :id: db459fc2-d34c-45cf-915a-1535406a9320 :description: Create {network, vcenter} source of single host and credential. Any valid IPv4 or dns name should be allowed to create a source. :steps: 1) Create host credential 2) Send POST with data to create the source using the credential to the source endpoint. :expectedresults: A new source entry is created with the data. """ cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred.create() src = Source( source_type=src_type, client=shared_client, hosts=[scan_host], credential_ids=[cred._id], ) src.create() # add the ids to the lists to destroy after the test is done cleanup.extend([cred, src]) assert_matches_server(src)
def test_negative_create_invalid_data(src_type, cleanup, shared_client, data): """Attempt to create a source with invalid data. The requests should be met with a 4XX response. :id: e8754fd4-8d03-4899-bfde-0fc587d78ae1 :description: Attempt to create sources missing required data. :steps: Attempt to create a source with invalid: a) creds b) host c) name :expectedresults: Error is thrown and no new source is created. """ cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred.create() cleanup.append(cred) data["credential_ids"] = cred._id if not data["credential_ids"] else [-1] src = Source( source_type=src_type, client=api.Client(response_handler=api.echo_handler), # unpack parametrized arguments **data ) create_response = src.create() assert create_response.status_code == 400 if create_response.status_code in [200, 201]: cleanup.append(src)
def test_create_multiple_hosts(shared_client, cleanup, scan_host): """Create a Network Source using multiple hosts. :id: 248f701c-b4d4-408a-80b0-c4863a8007e1 :description: Create a network source with multiple hosts :steps: 1) Create credential 2) Send POST with data to create network source using the credential to the source endpoint with multiple hosts, (list, IPv4 range, CIDR notation, or other ansible pattern) :expectedresults: The source is created. """ cred = Credential(cred_type=NETWORK_TYPE, client=shared_client, password=uuid4()) cred.create() src = Source( source_type=NETWORK_TYPE, client=shared_client, hosts=scan_host, credential_ids=[cred._id], ) src.create() # add the ids to the lists to destroy after the test is done cleanup.extend([cred, src]) src.hosts = RESULTING_HOST_FORMAT_DATA assert_matches_server(src)
def test_create_empty_str_host_valid(shared_client, cleanup): """Create a host manager source and then add host data with empty string. :id: 4bfbf5b0-81bd-48a3-8C57-bae55590285d :description: Create network source of multiple hosts including an empty string and credential. :steps: 1) Create a network credential 2) Create a source with multiple host including empty string :expectedresults: New source is created with all hosts except the empty string filtered out. """ empty_str_host_data = ["192.0.2.1", "192.0.2.10", ""] hosts_without_empty_str = ["192.0.2.1", "192.0.2.10"] # initialize & create original credential & source pwd_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, password=uuid4() ) pwd_cred.create() src = Source( source_type=NETWORK_TYPE, client=shared_client, hosts=empty_str_host_data, credential_ids=[pwd_cred._id], ) created_data = src.create() created_data = created_data.json() assert created_data["hosts"] == hosts_without_empty_str # add the ids to the lists to destroy after the test is done cleanup.extend([pwd_cred, src])
def test_negative_create_missing_data(src_type, cleanup, shared_client, field): """Attempt to create a source missing various data. The requests should be met with a 4XX response. :id: 4b176997-0be2-4bd8-81fd-8b4ef5045382 :description: Attempt to create sources missing required data. :steps: Attempt to create a source missing: a) a name b) hosts c) credential id's :expectedresults: Error is thrown and no new source is created. """ cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred.create() cleanup.append(cred) src = Source( source_type=src_type, client=api.Client(response_handler=api.echo_handler), hosts=["localhost"], credential_ids=[cred._id], ) # remove field from payload delattr(src, field) create_response = src.create() assert create_response.status_code == 400 if create_response.status_code in [200, 201]: cleanup.append(src)
def test_negative_create_multiple(src_type, shared_client, cleanup, scan_host): """Attempt to create a host manager Source using excess data. :id: 5a735a98-a437-4bcd-8abf-9d9644bcc045 :description: Any attempt to create a host manager source with multiple hosts, multiple credentials, or both should be rejected. :steps: 1) Create necessary credentials. 2) Send POST with data to create a host manager source using either multiple credentials or multiple hosts (could be list, IPv4 range, or ansible pattern like example[1-10].com) :expectedresults: An error is thrown and no new host is created. """ # initialize & create multiple credentials cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred2 = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred.create() cred2.create() # initialize source object using multiple hosts src = Source( source_type=src_type, client=shared_client, hosts=scan_host, credential_ids=[cred._id], ) assert_source_create_fails(src) # initialize source object using multiple creds src = Source( source_type=src_type, client=shared_client, hosts=VALID_HOST_DATA[0], credential_ids=[cred._id, cred2._id], ) assert_source_create_fails(src) # initialize source object using multiple creds & hosts src = Source( source_type=src_type, client=shared_client, hosts=scan_host, credential_ids=[cred._id, cred2._id], ) assert_source_create_fails(src) cleanup.extend([cred, cred2])
def test_update(shared_client, cleanup, scan_host, src_type): """Create a {network, vcenter} source and then update it. :id: 900dda70-6208-44f5-b64d-f6ca4db7dfa4 :description: Create {network, vcenter} source of single host and credential :steps: 1) Create host credential 2) Send POST with data to create {network, vcenter} source using the host credential to the source endpoint. 3) Add a host and a new credential and send and PUT to the server with the data :expectedresults: The source entry is created and updated. """ cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred.create() cleanup.append(cred) src = Source( source_type=src_type, client=shared_client, hosts=[scan_host], credential_ids=[cred._id], ) src.create() cleanup.append(src) assert_matches_server(src) src.hosts = ["example.com"] cred2 = Credential(cred_type=src_type, password=uuid4()) cred2.create() cleanup.append(cred2) src.credentials = [cred2._id] src.update() assert_matches_server(src)
def test_negative_update_invalid(src_type, shared_client, cleanup, scan_host, invalid_host): """Create a host manager source and then update it with invalid data. :id: d57d8481-54e3-4d9a-b330-80edc9364f37 :description: Create host manager source of single host and credential, then attempt to update it with multiple {hosts, credentials} :steps: 1) Create a valid host manager credential and source 2) Attempt to update with multiple {hosts, credentials} :expectedresults: An error is thrown and no new host is created. """ # initialize & create original credential & source pwd_cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) pwd_cred.create() src = Source( source_type=src_type, client=shared_client, hosts=scan_host, credential_ids=[pwd_cred._id], ) src.create() # Create extra credential for update cred2 = Credential(cred_type="network", client=shared_client, password=uuid4()) cred2.create() # add the ids to the lists to destroy after the test is done cleanup.extend([pwd_cred, src, cred2]) original_data = copy.deepcopy(src.fields()) src.client = api.Client(api.echo_handler) # Try to update with multiple credentials src.credentials = [pwd_cred._id, cred2._id] assert_source_update_fails(original_data, src) # Try to update with multiple hosts src.hosts = invalid_host assert_source_update_fails(original_data, src) # Try to update with multiple hosts & creds src.hosts = invalid_host src.credentials = [pwd_cred._id, cred2._id]
def test_create_multiple_creds_and_sources( shared_client, cleanup, scan_host, isolated_filesystem ): """Create a Network Source using multiple credentials. :id: 07f49731-0162-4eb1-b89a-3c95fddad428 :description: Create a network source with multiple credentials :steps: 1) Create multiple credentials using both sshkey and passwords 2) Send POST with data to create network source using the credentials using a list of sources using multiple formats (alphabetical name, CIDR, individual IPv4 address, etc.) :expectedresults: The source is created. """ sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() ssh_key_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}", ) ssh_key_cred.create() pwd_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, password=uuid4() ) pwd_cred.create() input_hosts = [scan_host] if isinstance(scan_host, list): input_hosts = scan_host src = Source( source_type=NETWORK_TYPE, client=shared_client, hosts=input_hosts, credential_ids=[ssh_key_cred._id, pwd_cred._id], ) src.create() # add the ids to the lists to destroy after the test is done cleanup.extend([ssh_key_cred, pwd_cred, src]) if isinstance(scan_host, list): src.hosts = RESULTING_HOST_FORMAT_DATA assert_matches_server(src)
def test_read_all(src_type, cleanup, shared_client): """After created, retrieve all network sources with GET to api. :id: e708362c-a289-46f1-ad05-724e3e4383d5 :description: The API should return list with all sources created when a GET request is sent to the {network, vcenter} sources endpoint. :steps: 1) Create collection of sources, saving the information. 2) Send GET request to {network, vcenter} source endpoint to get list of created {network, vcenter} sources 3) Confirm that all sources are in the list. :expectedresults: All sources are present in data returned by API. """ created_src_ids = set() # having a list of the sources locally will be helpful # for understanding failures as pytest will display the # data created_srcs = [] for _ in range(random.randint(2, 10)): # gen_valid_srcs will take care of cleanup src = gen_valid_source(cleanup, src_type, "localhost") created_srcs.append(src) created_src_ids.add(src._id) this_page = Source().list().json() while this_page: for source in this_page["results"]: if source["id"] in created_src_ids: created_src_ids.remove(source["id"]) next_page = this_page.get("next") if next_page: # must strip url of host information next_page = re.sub(r".*/api", "/api", next_page) this_page = shared_client.get(next_page).json() else: break # if we found everything we created, then the list should be empty if created_src_ids: raise AssertionError( "Expected to find all sources with correct data on server,\n" "but the following sources did not match expected or were" "missing from the server: \n" "{}".format(" ".join(created_src_ids)) )
def gen_valid_source(cleanup, src_type, hosts, create=True, exclude_hosts=None): """Create valid source.""" cred = Credential(cred_type=src_type, password=uuid4()) cred.create() cleanup.append(cred) source = Source(source_type=src_type, hosts=[hosts], credential_ids=[cred._id]) # QPC does not accept blank exclude_host values, only add it if not empty. if exclude_hosts is not None: source.exclude_hosts = [exclude_hosts] if create: source.create() cleanup.append(source) assert_matches_server(source) return source
def test_update_empty_str_host_valid(shared_client, cleanup): """Create a host manager source and then add host data with empty string. :id: 850b06ba-8e3f-4699-b24b-e75aad20a63a :description: Assert that we can update a source with hosts including an empty string, but the empty string is filtered out. :steps: 1) Create a valid network credential and source 2) Attempt to update with host list including empty string 3) Assert update is made but with the empty string filtered out. :expectedresults: Source is updated with only valid host list. """ empty_str_host_data = ["192.0.2.1", "192.0.2.10", ""] hosts_without_empty_str = ["192.0.2.1", "192.0.2.10"] # initialize & create original credential & source pwd_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, password=uuid4() ) pwd_cred.create() src = Source( source_type=NETWORK_TYPE, client=shared_client, hosts=["127.0.0.1"], credential_ids=[pwd_cred._id], ) src.create() # add the ids to the lists to destroy after the test is done cleanup.extend([pwd_cred, src]) src.hosts = empty_str_host_data updated_data = src.update().json() assert updated_data["hosts"] == hosts_without_empty_str
def test_create_multiple_creds(shared_client, cleanup, scan_host, isolated_filesystem): """Create a Network Source using multiple credentials. :id: dcf6ea99-c6b1-493d-9db8-3ec0ea09b5e0 :description: Create a network source with multiple credentials :steps: 1) Create multiple credentials using both sshkey and passwords 2) Send POST with data to create network source using the credentials :expectedresults: The source is created. """ sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() ssh_key_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}", ) ssh_key_cred.create() pwd_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, password=uuid4() ) pwd_cred.create() src = Source( source_type=NETWORK_TYPE, client=shared_client, hosts=[scan_host], credential_ids=[ssh_key_cred._id, pwd_cred._id], ) src.create() # add the ids to the lists to destroy after the test is done cleanup.extend([ssh_key_cred, pwd_cred, src]) assert_matches_server(src)
def test_negative_update_invalid( shared_client, cleanup, isolated_filesystem, scan_host ): """Create a network source and then update it with invalid data. :id: e0d72f2b-2490-445e-b646-f06ceb4ad23f :description: Create network source of single host and credential, then attempt to update it with multiple invalid {hosts, credentials} :steps: 1) Create a valid network credential and source 2) Attempt to update with multiple invalid {hosts, credentials} :expectedresults: An error is thrown and no new host is created. """ sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() net_cred = Credential( cred_type=NETWORK_TYPE, client=shared_client, ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}", ) net_cred.create() sat_cred = Credential(cred_type="satellite", client=shared_client, password=uuid4()) sat_cred.create() src = Source( source_type=NETWORK_TYPE, client=shared_client, hosts=[scan_host], credential_ids=[net_cred._id], ) src.create() # add the ids to the lists to destroy after the test is done cleanup.extend([net_cred, sat_cred, src]) original_data = copy.deepcopy(src.fields()) src.client = api.Client(api.echo_handler) # Try to update with invalid credential type src.credentials = [sat_cred._id] assert_source_update_fails(original_data, src) src.hosts = ["1**2@33^"] assert_source_update_fails(original_data, src)
def test_create_exclude_hosts_negative(shared_client, cleanup, scan_host, src_type): """Attempt to create a source with excluded hosts with an invalid source type. :id: 52ba8847-81d7-4c8a-a5bd-1f946f5f39b5 :description: Attempt to create a source with exclude_hosts with an invalid source type, like vcenter or satellite. :steps: 1) Create host credential 2) Send POST with data to create the source using the credential to the endpoint, with the exclude_host option and invalid source type. :expectedresults: Creation of the source fails with a message about an invalid source type. """ cred = Credential(cred_type=src_type, client=shared_client, password=uuid4()) cred.create() cleanup.append(cred) src = Source( source_type=src_type, client=shared_client, hosts=[scan_host], credential_ids=[cred._id], ) src.exclude_hosts = ["10.10.10.10"] assert_source_create_fails(src, src_type)
def test_equivalent_network(self): """If a hostname is specified in the config file, we use it.""" with mock.patch.object(config, "_CONFIG", self.config): client = api.Client(authenticate=False) src = Source( source_type="network", name=MOCK_SOURCE["name"], hosts=MOCK_SOURCE["hosts"], credential_ids=[MOCK_SOURCE["credentials"][0]["id"]], client=client, ) src._id = MOCK_SOURCE["id"] self.assertTrue(src.equivalent(MOCK_SOURCE)) self.assertTrue(src.equivalent(src)) with self.assertRaises(TypeError): src.equivalent([])
def test_equivalent_satellite(self): """If a hostname is specified in the config file, we use it.""" with mock.patch.object(config, "_CONFIG", self.config): client = api.Client(authenticate=False) p = Source( source_type="satellite", name=MOCK_SAT6_SOURCE["name"], hosts=MOCK_SAT6_SOURCE["hosts"], credential_ids=[MOCK_SAT6_SOURCE["credentials"][0]["id"]], options=MOCK_SAT6_SOURCE["options"], port=443, client=client, ) p._id = MOCK_SAT6_SOURCE["id"] self.assertTrue(p.equivalent(MOCK_SAT6_SOURCE)) self.assertTrue(p.equivalent(p)) with self.assertRaises(TypeError): p.equivalent([])
def get_source(source_type, cleanup): """Retrieve a single network source if available from config file. :param source_type: The type of source to be created. This function retreives one source of matching type from the config file. :param cleanup: The "cleanup" list that tests use to destroy objects after a test has run. The "cleanup" list is provided by the py.test fixture of the same name defined in camayoc/tests/qpc/conftest.py. Sources are retreived from the following section and are assumed to be available on demand and do not require their power state to be managed. The expected configuration in the Camayoc's configuration file is as follows:: qpc: # other needed qpc config data sources: - hosts: - '127.0.0.1' name: local type: network credentials: - root The credential listed is assumed to be in the top level 'credentials' section. This source is meant to be used for tests where we do not care about the results of the scan, for example tests that assert we can pause and restart a scan. :returns: camayoc.qpc_models.Source of the same type that was requested with the 'source_type' parameter. The returned source has been created on server and has all credentials listed in config file created and associtated with it. """ cfg = config.get_config() cred_list = cfg.get("credentials", []) src_list = cfg.get("qpc", {}).get("sources", []) config_src = {} if not (src_list and cred_list): return for src in src_list: if src.get("type") == source_type: config_src = src if config_src: config_src.setdefault("credential_ids", []) src_creds = config_src.get("credentials") for cred in src_creds: for config_cred in cred_list: if cred == config_cred["name"]: server_cred = Credential(cred_type=source_type, username=config_cred["username"]) if config_cred.get("password"): server_cred.password = config_cred["password"] else: server_cred.ssh_keyfile = config_cred["sshkeyfile"] server_cred.create() cleanup.append(server_cred) config_src["credential_ids"].append(server_cred._id) server_src = Source( hosts=config_src["hosts"], credential_ids=config_src["credential_ids"], source_type=source_type, ) if config_src.get("options"): server_src.options = config_src.get("options") server_src.create() cleanup.append(server_src) return server_src
def create_source(source_info, cleanup): """Given info about source from config file, create it and return id.""" src = Source(**source_info) src.create() cleanup.append(src) return src._id