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_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_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_negative_create_key_and_pass(cleanup, isolated_filesystem): """Attempt to create a network credential with sshkey and password. The request should be met with a 4XX response. :id: 22a2ca65-5f9d-4c43-89ad-d7ab53223896 :description: Create a network credential with username, sshkey, and password. :steps: Send POST with necessary data to the credential api endpoint. :expectedresults: Error is thrown and no new network credential is created. """ ssh_keyfile = Path(uuid4()) ssh_keyfile.touch() client = api.Client(api.echo_handler) cred = Credential( cred_type="network", client=client, ssh_keyfile=str(ssh_keyfile.resolve()), password=uuid4(), ) response = cred.create() assert response.status_code == 400 assert "either a password or an ssh_keyfile, not both" in response.text assert cred._id is None
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(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_type_mismatch(src_type, cleanup, shared_client): """Attempt to create sources with credentials of the wrong type. For example, if we create a 'network' typed credential, we can not create a 'vcenter' typed source using this credential. :id: 89bc1bb5-127b-48da-b106-82cd1ef7e00a :description: Test that we cannot create a source with the wrong type of credential. :steps: 1) Create a credential of one type 2) Attempt to create a source with that credential of a different type :expectedresults: An error is thrown and no new source is created. :caseautomation: notautomated """ src = gen_valid_source(cleanup, src_type, "localhost", create=False) other_types = set(QPC_SOURCE_TYPES).difference(set((src_type,))) other_cred = Credential( password=uuid4(), cred_type=random.choice(list(other_types)) ) other_cred.create() cleanup.append(other_cred) src.credentials = [other_cred._id] src.client = api.Client(api.echo_handler) create_response = src.create() assert create_response.status_code == 400 if create_response.status_code in [200, 201]: cleanup.append(src) assert "source_type" in create_response.json().keys()
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_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_update_sshkey_to_password(shared_client, cleanup, isolated_filesystem): """Create a network credential using password and switch it to use sshkey. :id: d24a54b5-3d8c-44e4-a0ae-61584a15b127 :description: Create a network credential with a sshkey, then update it to use a password. :steps: 1) Create a network credential with a username and sshkey. 2) Update the network credential deleting sshkey and updating password. 3) Confirm network credential has been updated. :expectedresults: The network credential is updated. """ sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() cred = Credential(cred_type="network", ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}") cred.create() # add the id to the list to destroy after the test is done cleanup.append(cred) assert_matches_server(cred) cred.client.response_handler = api.echo_handler cred.password = uuid4() cred.ssh_keyfile = None cred.update() assert_matches_server(cred)
def test_update_password_to_sshkeyfile(shared_client, cleanup, isolated_filesystem): """Create a network credential using password and switch it to use sshkey. :id: 6e557092-192b-4f75-babc-abc5774fe965 :description: Create a network credential with password, then update it to use a sshkey. :steps: 1) Create a network credential with a username and password. 2) Update the network credential deleting password and adding sshkey. 3) Confirm network credential has been updated. :expectedresults: The network credential is updated. """ cred = Credential(cred_type="network", client=shared_client, password=uuid4()) cred.create() # add the id to the list to destroy after the test is done cleanup.append(cred) assert_matches_server(cred) sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() cred.ssh_keyfile = f"/sshkeys/{tmp_dir}/{sshkeyfile_name}" cred.password = None cred.update() assert_matches_server(cred)
def test_negative_update_to_invalid(shared_client, cleanup, isolated_filesystem): """Attempt to update valid credential with invalid data. :id: c34ea917-ee36-4b93-8907-24a5f87bbed3 :description: Create valid network credentials, then attempt to update to be invalid. :steps: 1) Create valid credentials with passwords or sshkey. 2) Update the network credentials: a) using both password and sshkey b) missing both password and sshkey :expectedresults: Error codes are returned and the network credentials are not updated. """ sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() cred = Credential( cred_type="network", client=shared_client, ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}", ) cred.create() # add the id to the list to destroy after the test is done cleanup.append(cred) assert_matches_server(cred) cred.client = api.Client(api.echo_handler) # Try to update with both sshkeyfile and password cred.password = uuid4() response = cred.update() assert response.status_code == 400 assert "either a password or an ssh_keyfile, not both" in response.text cred.password = None assert_matches_server(cred) # Try to update with both sshkeyfile and password missing old = cred.ssh_keyfile del cred.ssh_keyfile response = cred.update() assert response.status_code == 400 assert "must have either a password or an ssh_keyfile" in response.text cred.ssh_keyfile = old assert_matches_server(cred)
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_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_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 and uses a become method. :steps: Send a POST to the credential endpoint with data. :expectedresults: A new network credential is created. """ 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)
def test_create_with_sshkey(shared_client, cleanup, isolated_filesystem): """Create a network credential with username and sshkey. :id: ab6fd574-2e9f-46b8-847d-17b23c19fdd2 :description: Create a network credential with a user name and sshkey :steps: Send POST with necessary data to documented api endpoint. :expectedresults: A new network credential entry is created with the data. """ sshkeyfile_name = utils.uuid4() tmp_dir = os.path.basename(os.getcwd()) sshkeyfile = Path(sshkeyfile_name) sshkeyfile.touch() cred = Credential( cred_type="network", client=shared_client, ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}", ) cred.create() # add the id to the list to destroy after the test is done cleanup.append(cred) assert_matches_server(cred)
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)
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_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)
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_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_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_equivalent(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) h = Credential( cred_type="network", username=MOCK_CREDENTIAL["username"], name=MOCK_CREDENTIAL["name"], client=client, ) h._id = MOCK_CREDENTIAL["id"] self.assertTrue(h.equivalent(MOCK_CREDENTIAL)) self.assertTrue(h.equivalent(h)) with self.assertRaises(TypeError): h.equivalent([])
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 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_cred(cred_info, cleanup): """Given info about cred from config file, create it and return id.""" c = Credential(**cred_info) c.create() cleanup.append(c) return c._id