diff --git a/camayoc/tests/qpc/ui/test_credentials.py b/camayoc/tests/qpc/ui/test_credentials.py index eee4c21d..49d01b2b 100644 --- a/camayoc/tests/qpc/ui/test_credentials.py +++ b/camayoc/tests/qpc/ui/test_credentials.py @@ -14,6 +14,7 @@ from littletable import Table from camayoc.qpc_models import Credential +from camayoc.types.ui import AnsibleCredentialFormDTO from camayoc.types.ui import CredentialFormDTO from camayoc.types.ui import NetworkCredentialFormDTO from camayoc.types.ui import PlainNetworkCredentialFormDTO @@ -29,6 +30,7 @@ CREDENTIAL_TYPE_MAP = { SatelliteCredentialFormDTO: CredentialTypes.SATELLITE, VCenterCredentialFormDTO: CredentialTypes.VCENTER, + AnsibleCredentialFormDTO: CredentialTypes.ANSIBLE, } diff --git a/camayoc/tests/qpc/ui/test_endtoend.py b/camayoc/tests/qpc/ui/test_endtoend.py index 994bdb45..bb550dd3 100644 --- a/camayoc/tests/qpc/ui/test_endtoend.py +++ b/camayoc/tests/qpc/ui/test_endtoend.py @@ -56,10 +56,6 @@ def create_endtoend_dtos(source_name, data_provider): def source_names(): for source_definition in settings.sources: - # FIXME: should add Ansible to UI, not ignore it - if source_definition.type == "ansible": - continue - fixture_id = f"{source_definition.name}-{source_definition.type}" yield pytest.param(source_definition.name, id=fixture_id) diff --git a/camayoc/tests/qpc/ui/test_sources.py b/camayoc/tests/qpc/ui/test_sources.py index 6889818e..90b35588 100644 --- a/camayoc/tests/qpc/ui/test_sources.py +++ b/camayoc/tests/qpc/ui/test_sources.py @@ -13,6 +13,7 @@ import pytest from camayoc.qpc_models import Source +from camayoc.types.ui import AnsibleSourceFormDTO from camayoc.types.ui import NetworkSourceFormDTO from camayoc.types.ui import SatelliteSourceFormDTO from camayoc.types.ui import SourceFormDTO @@ -33,6 +34,7 @@ ], SatelliteSourceFormDTO: ["127.0.0.1", "examplesatellite.sonar.com"], VCenterSourceFormDTO: ["127.0.0.1", "examplevcenter.sonar.com"], + AnsibleSourceFormDTO: ["127.0.0.1", "exampleansible.sonar.com"], } @@ -40,6 +42,7 @@ NetworkSourceFormDTO: "network", SatelliteSourceFormDTO: "satellite", VCenterSourceFormDTO: "vcenter", + AnsibleSourceFormDTO: "ansible", } @@ -47,6 +50,7 @@ NetworkSourceFormDTO: SourceTypes.NETWORK_RANGE, SatelliteSourceFormDTO: SourceTypes.SATELLITE, VCenterSourceFormDTO: SourceTypes.VCENTER_SERVER, + AnsibleSourceFormDTO: SourceTypes.ANSIBLE_CONTROLLER, } diff --git a/camayoc/types/ui.py b/camayoc/types/ui.py index 7b37d71c..9107fd56 100644 --- a/camayoc/types/ui.py +++ b/camayoc/types/ui.py @@ -167,8 +167,22 @@ def from_model(cls, model: Credential): return cls(credential_name=model.name, username=model.username, password=model.password) +@frozen +class AnsibleCredentialFormDTO: + credential_name: str + username: str + password: str + + @classmethod + def from_model(cls, model: Credential): + return cls(credential_name=model.name, username=model.username, password=model.password) + + CredentialFormDTO = Union[ - NetworkCredentialFormDTO, SatelliteCredentialFormDTO, VCenterCredentialFormDTO + NetworkCredentialFormDTO, + SatelliteCredentialFormDTO, + VCenterCredentialFormDTO, + AnsibleCredentialFormDTO, ] @@ -192,6 +206,9 @@ def from_model(cls, model: Credential): case "vcenter": credential_type = CredentialTypes.VCENTER credential_form_dto = VCenterCredentialFormDTO.from_model(model) + case "ansible": + credential_type = CredentialTypes.ANSIBLE + credential_form_dto = AnsibleCredentialFormDTO.from_model(model) case _: raise ValueError(f"Can't create Credential UI DTO from {model}") return cls(credential_type, credential_form_dto) @@ -256,10 +273,29 @@ def from_model(cls, model: Source): ) +@frozen +class AnsibleSourceFormDTO: + source_name: str + address: str + credentials: list[str] + connection: Optional[SourceConnectionTypes] = None + verify_ssl: Optional[bool] = None + + @classmethod + def from_model(cls, model: Source): + return cls( + source_name=model.name, + address=model.hosts[0], + credentials=model.credentials, + verify_ssl=model.options.get("ssl_cert_verify"), + ) + + SourceFormDTO = Union[ NetworkSourceFormDTO, SatelliteSourceFormDTO, VCenterSourceFormDTO, + AnsibleSourceFormDTO, ] @@ -280,6 +316,9 @@ def from_model(cls, model: Source): case "vcenter": source_type = SourceTypes.VCENTER_SERVER source_form_dto = VCenterSourceFormDTO.from_model(model) + case "ansible": + source_type = SourceTypes.ANSIBLE_CONTROLLER + source_form_dto = AnsibleSourceFormDTO.from_model(model) case _: raise ValueError(f"Can't create Source UI DTO from {model}") return cls(SelectSourceDTO(source_type), source_form_dto) diff --git a/camayoc/ui/data_factories.py b/camayoc/ui/data_factories.py index 93a787fa..043f0802 100644 --- a/camayoc/ui/data_factories.py +++ b/camayoc/ui/data_factories.py @@ -10,6 +10,8 @@ from camayoc.data_provider import DataProvider from camayoc.types.ui import AddCredentialDTO from camayoc.types.ui import AddSourceDTO +from camayoc.types.ui import AnsibleCredentialFormDTO +from camayoc.types.ui import AnsibleSourceFormDTO from camayoc.types.ui import CredentialFormDTO from camayoc.types.ui import LoginFormDTO from camayoc.types.ui import NetworkCredentialFormDTO @@ -136,6 +138,15 @@ class Meta: password = factory.Faker("password") +class AnsibleCredentialFormDTOFactory(factory.Factory): + class Meta: + model = AnsibleCredentialFormDTO + + credential_name = factory.Faker("text", max_nb_chars=56) + username = factory.Faker("user_name") + password = factory.Faker("password") + + class CredentialFormDTOFactory(UnionDTOFactory): class Meta: model = CredentialFormDTO @@ -149,6 +160,8 @@ def _type_dependent_credential_form_factory(obj): return SatelliteCredentialFormDTOFactory elif credential_type == CredentialTypes.VCENTER: return VCenterCredentialFormDTOFactory + elif credential_type == CredentialTypes.ANSIBLE: + return AnsibleCredentialFormDTOFactory class AddCredentialDTOFactory(factory.Factory): @@ -255,6 +268,32 @@ def credentials(self): verify_ssl = factory.LazyAttribute(_verify_ssl_based_on_connection) +class AnsibleSourceFormDTOFactory(factory.Factory): + class Meta: + model = AnsibleSourceFormDTO + + class Params: + credentials_num = 1 + + source_name = factory.Faker("text", max_nb_chars=56) + address = factory.Faker("ipv4_private") + + @factory.lazy_attribute + def credentials(self): + data_provider = DataProvider() + network_credential_generator = data_provider.credentials.new_many( + {"type": "ansible"}, data_only=False + ) + cred_names = [] + for _ in range(self.credentials_num): + cred = next(network_credential_generator) + cred_names.append(cred.name) + return cred_names + + connection = factory.Faker("random_element", elements=list(SourceConnectionTypes)) + verify_ssl = factory.LazyAttribute(_verify_ssl_based_on_connection) + + class SourceFormDTOFactory(UnionDTOFactory): class Meta: model = SourceFormDTO @@ -268,6 +307,8 @@ def _source_type_dependent_source_form_factory(obj): return SatelliteSourceFormDTOFactory elif source_type == SourceTypes.VCENTER_SERVER: return VCenterSourceFormDTOFactory + elif source_type == SourceTypes.ANSIBLE_CONTROLLER: + return AnsibleSourceFormDTOFactory class AddSourceDTOFactory(factory.Factory): diff --git a/camayoc/ui/enums.py b/camayoc/ui/enums.py index f4a576b0..a4b7cb84 100644 --- a/camayoc/ui/enums.py +++ b/camayoc/ui/enums.py @@ -30,6 +30,7 @@ class CredentialTypes(StrEnum): NETWORK = auto() SATELLITE = auto() VCENTER = auto() + ANSIBLE = auto() class NetworkCredentialAuthenticationTypes(StrEnum): @@ -52,6 +53,7 @@ class SourceTypes(StrEnum): NETWORK_RANGE = "network" SATELLITE = "satellite" VCENTER_SERVER = "vcenter" + ANSIBLE_CONTROLLER = "ansible" class SourceConnectionTypes(StrEnum): diff --git a/camayoc/ui/models/pages/credentials.py b/camayoc/ui/models/pages/credentials.py index 9ee7e210..6d581295 100644 --- a/camayoc/ui/models/pages/credentials.py +++ b/camayoc/ui/models/pages/credentials.py @@ -3,6 +3,7 @@ from typing import overload from camayoc.types.ui import AddCredentialDTO +from camayoc.types.ui import AnsibleCredentialFormDTO from camayoc.types.ui import NetworkCredentialFormDTO from camayoc.types.ui import SatelliteCredentialFormDTO from camayoc.types.ui import VCenterCredentialFormDTO @@ -88,6 +89,22 @@ def fill(self, data: VCenterCredentialFormDTO): return self +class AnsibleCredentialForm(CredentialForm): + class FormDefinition: + credential_name = InputField("input[data-ouia-component-id=cred_name]") + username = InputField("input[data-ouia-component-id=username]") + password = InputField("input[data-ouia-component-id=password]") + + @overload + def fill(self, data: AnsibleCredentialFormDTO): + ... + + @record_action + def fill(self, data: AnsibleCredentialFormDTO): + super().fill(data) + return self + + class CredentialsMainPage(MainPageMixin): @service def add_credential(self, data: AddCredentialDTO) -> CredentialsMainPage: @@ -111,6 +128,10 @@ def open_add_credential(self, source_type: CredentialTypes) -> CredentialForm: "selector": f"{create_credential_button} ~ ul li:nth-of-type(4) a", "class": VCenterCredentialForm, }, + CredentialTypes.ANSIBLE: { + "selector": f"{create_credential_button} ~ ul li:nth-of-type(5) a", + "class": AnsibleCredentialForm, + }, } selector, cls = source_type_map.get(source_type).values() diff --git a/camayoc/ui/models/pages/sources.py b/camayoc/ui/models/pages/sources.py index b5fce7d3..6a8ba5da 100644 --- a/camayoc/ui/models/pages/sources.py +++ b/camayoc/ui/models/pages/sources.py @@ -3,6 +3,7 @@ from typing import overload from camayoc.types.ui import AddSourceDTO +from camayoc.types.ui import AnsibleSourceFormDTO from camayoc.types.ui import NetworkSourceFormDTO from camayoc.types.ui import NewScanFormDTO from camayoc.types.ui import SatelliteSourceFormDTO @@ -57,6 +58,7 @@ def fill(self, data: SelectSourceDTO): SourceTypes.NETWORK_RANGE: NetworkRangeSourceCredentialsForm, SourceTypes.SATELLITE: SatelliteSourceCredentialsForm, SourceTypes.VCENTER_SERVER: VCenterSourceCredentialsForm, + SourceTypes.ANSIBLE_CONTROLLER: AnsibleSourceCredentialsForm, } next_step_class = source_type_map.get(data.source_type) setattr(self, "NEXT_STEP_RESULT_CLASS", next_step_class) @@ -139,6 +141,26 @@ def fill(self, data: VCenterSourceFormDTO): return self +class AnsibleSourceCredentialsForm(SourceCredentialsForm): + class FormDefinition: + source_name = InputField("input[data-ouia-component-id=name]") + address = InputField("input[data-ouia-component-id=hosts_single]") + credentials = MultipleSelectField( + "div[data-ouia-component-id=add_credentials_select] > button" + ) + connection = SelectField("div[data-ouia-component-id=options_ssl_protocol] > button") + verify_ssl = CheckboxField("input[data-ouia-component-id=options_ssl_cert]") + + @overload + def fill(self, data: AnsibleSourceFormDTO): + ... + + @record_action + def fill(self, data: AnsibleSourceFormDTO): + super().fill(data) + return self + + class ResultForm(WizardStep, AbstractPage): NEXT_STEP_LOCATOR = ".pf-c-wizard__footer button.pf-m-primary" NEXT_STEP_RESULT_CLASS = Pages.SOURCES