diff --git a/app/api/network.py b/app/api/network.py index 2c8b3d4e2a58117dde385a51bcdad69b46603aec..99c3640de05efc88c707fcd32d45ec6f4b96397c 100644 --- a/app/api/network.py +++ b/app/api/network.py @@ -212,6 +212,7 @@ def create_host(): :jsonparam name: hostname :jsonparam device_type: Physical|Virtual|... + :jsonparam is_ioc: True|False (optional) :jsonparam description: (optional) description :jsonparam items: (optional) list of items ICS id linked to the host :jsonparam ansible_vars: (optional) Ansible variables diff --git a/app/defaults.py b/app/defaults.py index ff6f2ab2928be8a5bd2f8cc90c5ab90998bbdef5..b140097add5b1995c9ac64b72f31344faf16464d 100644 --- a/app/defaults.py +++ b/app/defaults.py @@ -26,5 +26,4 @@ defaults = [ models.DeviceType(name="MicroTCA"), models.DeviceType(name="VME"), models.DeviceType(name="PLC"), - models.Tag(name="IOC", admin_only=False), ] diff --git a/app/factory.py b/app/factory.py index cd6ab2f5cf3f3992f3436da8ea82819299c15ada..ce07c1c9dd0156eb03ea5bcb988a990ef7e53284 100644 --- a/app/factory.py +++ b/app/factory.py @@ -141,7 +141,6 @@ def create_app(config=None): admin.add_view(AdminModelView(models.Interface, db.session)) admin.add_view(AdminModelView(models.Mac, db.session)) admin.add_view(AdminModelView(models.Cname, db.session)) - admin.add_view(AdminModelView(models.Tag, db.session)) admin.add_view(TaskAdmin(models.Task, db.session, endpoint="tasks")) app.register_blueprint(main) diff --git a/app/models.py b/app/models.py index c766762e6cd140ca463ba0418f088cda2a933f61..e7d9156f93eaa6ecba854943db973318fa5ef06f 100644 --- a/app/models.py +++ b/app/models.py @@ -35,7 +35,6 @@ from .validators import ( VLAN_NAME_RE, MAC_ADDRESS_RE, DEVICE_TYPE_RE, - TAG_RE, ) from . import utils, search @@ -905,28 +904,6 @@ class Network(CreatedMixin, db.Model): return d -# Table required for Many-to-Many relationships between interfaces and tags -interfacetags_table = db.Table( - "interfacetags", - db.Column("tag_id", db.Integer, db.ForeignKey("tag.id"), primary_key=True), - db.Column( - "interface_id", db.Integer, db.ForeignKey("interface.id"), primary_key=True - ), -) - - -class Tag(QRCodeMixin, db.Model): - admin_only = db.Column(db.Boolean, nullable=False, default=False) - - @validates("name") - def validate_name(self, key, string): - """Ensure the name field matches the required format""" - if string is not None: - if TAG_RE.fullmatch(string) is None: - raise ValidationError(f"'{string}' is an invalid tag name") - return string - - class DeviceType(db.Model): __tablename__ = "device_type" id = db.Column(db.Integer, primary_key=True) @@ -991,6 +968,7 @@ class AnsibleGroupType(Enum): NETWORK_SCOPE = "NETWORK_SCOPE" NETWORK = "NETWORK" DEVICE_TYPE = "DEVICE_TYPE" + IOC = "IOC" def __str__(self): return self.name @@ -1060,6 +1038,8 @@ class AnsibleGroup(CreatedMixin, db.Model): .order_by(Host.name) .all() ) + if self.type == AnsibleGroupType.IOC: + return Host.query.filter(Host.is_ioc.is_(True)).order_by(Host.name).all() @hosts.setter def hosts(self, value): @@ -1110,7 +1090,6 @@ class Host(CreatedMixin, SearchableMixin, db.Model): "host": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, "cnames": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, "domain": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, - "tags": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, "device_type": { "type": "text", "fields": {"keyword": {"type": "keyword"}}, @@ -1129,6 +1108,7 @@ class Host(CreatedMixin, SearchableMixin, db.Model): device_type_id = db.Column( db.Integer, db.ForeignKey("device_type.id"), nullable=False ) + is_ioc = db.Column(db.Boolean, nullable=False, default=False) ansible_vars = db.Column(postgresql.JSONB) # 1. Set cascade to all (to add delete) and delete-orphan to delete all interfaces @@ -1174,13 +1154,6 @@ class Host(CreatedMixin, SearchableMixin, db.Model): ] super().__init__(**kwargs) - @property - def is_ioc(self): - for interface in self.interfaces: - if interface.is_ioc: - return True - return False - @property def model(self): """Return the model of the first linked item""" @@ -1295,12 +1268,6 @@ class Interface(CreatedMixin, db.Model): cascade="all, delete, delete-orphan", lazy="joined", ) - tags = db.relationship( - "Tag", - secondary=interfacetags_table, - lazy="subquery", - backref=db.backref("interfaces", lazy=True), - ) def __init__(self, **kwargs): # Always set self.host and not self.host_id to call validate_name @@ -1382,10 +1349,7 @@ class Interface(CreatedMixin, db.Model): @property def is_ioc(self): - for tag in self.tags: - if tag.name == "IOC": - return True - return False + return self.is_main and self.host.is_ioc @property def is_main(self): @@ -1410,7 +1374,6 @@ class Interface(CreatedMixin, db.Model): "host": utils.format_field(self.host), "cnames": [str(cname) for cname in self.cnames], "domain": str(self.network.domain), - "tags": [str(tag) for tag in self.tags], } ) if self.host: diff --git a/app/network/forms.py b/app/network/forms.py index fad2c3c44ccb1d1f3b3e46011ac10903ec667a50..644d83b964368e7a6c5c475115fc822ab0af1359 100644 --- a/app/network/forms.py +++ b/app/network/forms.py @@ -143,6 +143,7 @@ class HostForm(CSEntryForm): ) description = TextAreaField("Description") device_type_id = SelectField("Device Type") + is_ioc = BooleanField("IOC", default=False) ansible_vars = YAMLField( "Ansible vars", description="Enter variables in YAML format. See https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html", @@ -204,18 +205,10 @@ class InterfaceForm(CSEntryForm): UniqueAccrossModels([models.Host, models.Interface]), ], ) - tags = SelectMultipleField("Tags", coerce=utils.coerce_to_str_or_none) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.host_id.choices = utils.get_model_choices(models.Host) - if current_user.is_admin: - tags_query = models.Tag.query - else: - tags_query = models.Tag.query.filter(models.Tag.admin_only.is_(False)) - self.tags.choices = utils.get_model_choices( - models.Tag, attr="name", query=tags_query - ) # Only return the networks the user has access to self.network_id.choices = [ (str(network.id), network.vlan_name) diff --git a/app/network/views.py b/app/network/views.py index 11f0f2a5d5e661cf681bf449c9a084379c3b38dd..af320d307343e39ff95b5ba4f9ae05ff76c50264 100644 --- a/app/network/views.py +++ b/app/network/views.py @@ -85,22 +85,17 @@ def create_host(): host = models.Host( name=form.name.data, device_type=models.DeviceType.query.get(form.device_type_id.data), + is_ioc=form.is_ioc.data, description=form.description.data or None, ansible_vars=form.ansible_vars.data or None, ansible_groups=ansible_groups, ) - # The total number of tags will always be quite small - # It's more efficient to retrieve all of them in one query - # and do the filtering here - all_tags = models.Tag.query.all() - tags = [tag for tag in all_tags if str(tag.id) in form.tags.data] interface = models.Interface( host=host, name=form.name.data, ip=form.ip.data, mac=form.mac.data, network=network, - tags=tags, ) interface.cnames = [ models.Cname(name=name) for name in form.cnames_string.data.split() @@ -239,6 +234,7 @@ def edit_host(name): try: host.name = form.name.data host.device_type = models.DeviceType.query.get(form.device_type_id.data) + host.is_ioc = form.is_ioc.data host.description = form.description.data or None host.ansible_vars = form.ansible_vars.data or None host.ansible_groups = [ @@ -281,11 +277,6 @@ def create_interface(hostname): network = models.Network.query.get(form.network_id.data) if not current_user.has_access_to_network(network): abort(403) - # The total number of tags will always be quite small - # It's more efficient to retrieve all of them in one query - # and do the filtering here - all_tags = models.Tag.query.all() - tags = [tag for tag in all_tags if str(tag.id) in form.tags.data] try: interface = models.Interface( host=host, @@ -293,7 +284,6 @@ def create_interface(hostname): ip=form.ip.data, mac=form.mac.data, network=network, - tags=tags, ) interface.cnames = [ models.Cname(name=name) for name in form.cnames_string.data.split() @@ -339,12 +329,6 @@ def edit_interface(name): ips = [interface.ip] ips.extend([str(address) for address in interface.network.available_ips()]) form.ip.choices = utils.get_choices(ips) - # Passing tags as kwarg to the InterfaceForm doesn't work because - # obj takes precedence (but interface.tags contain Tag instances and not id) - # We need to update the default values. Calling process is required. - # See https://stackoverflow.com/questions/5519729/wtforms-how-to-select-options-in-selectmultiplefield - form.tags.default = [tag.id for tag in interface.tags] - form.tags.process(request.form) if form.validate_on_submit(): network = models.Network.query.get(form.network_id.data) if not current_user.has_access_to_network(network): @@ -378,9 +362,6 @@ def edit_interface(name): return render_template( "network/edit_interface.html", form=form, hostname=interface.host.name ) - all_tags = models.Tag.query.all() - tags = [tag for tag in all_tags if str(tag.id) in form.tags.data] - interface.tags = tags # Mark the host as "dirty" to add it to the session so that it will # be re-indexed sa.orm.attributes.flag_modified(interface.host, "interfaces") diff --git a/app/static/js/hosts.js b/app/static/js/hosts.js index b6c590b3912e615fe0ac7fe72cde3e752ed406df..75ac21571872027148100dc9d8c003b7666ec8fd 100644 --- a/app/static/js/hosts.js +++ b/app/static/js/hosts.js @@ -45,27 +45,7 @@ $(document).ready(function() { } } - // Select the IOC tag by default depending on the device type - function update_default_tags(device_type) { - var tags_selectize = $("#tags")[0].selectize; - var ioc_device_types = ["PhysicalMachine", "VirtualMachine", "MicroTCA", "VME"]; - var is_ioc_selected = $.inArray(device_type, ioc_device_types) > -1; - var ioc_search = tags_selectize.search("IOC").items[0] - if ( ioc_search === undefined ) { - // IOC is already selected - var ioc_value = $("div .item:contains('IOC')").data("value"); - } else { - var ioc_value = ioc_search.id; - } - if ( is_ioc_selected ) { - tags_selectize.addItem(ioc_value, false); - } else { - tags_selectize.removeItem(ioc_value, false); - } - } - // And check / uncheck random_mac checkbox - // and update default tags function update_device_type_attributes() { var device_type = $("#device_type_id option:selected").text(); if( device_type.startsWith("Virtual") ) { @@ -73,7 +53,6 @@ $(document).ready(function() { } else { $("#random_mac").prop("checked", false).change(); } - update_default_tags(device_type); } // If random_mac is checked, generate a random address diff --git a/app/templates/network/create_host.html b/app/templates/network/create_host.html index 15d844c8a87eb0e7fe7a5890aaa8c5df39e07b7d..f234cd8b29b2450ac81ee40b8d0ea510c62382ad 100644 --- a/app/templates/network/create_host.html +++ b/app/templates/network/create_host.html @@ -8,13 +8,13 @@ {{ form.hidden_tag() }} {{ render_field(form.name, class_="text-lowercase") }} {{ render_field(form.device_type_id, class_="selectize-default") }} + {{ render_field(form.is_ioc) }} {{ render_field(form.description) }} {{ render_field(form.network_id, class_="selectize-default") }} {{ render_field(form.ip) }} {{ render_field(form.random_mac) }} {{ render_field(form.mac) }} {{ render_field(form.cnames_string) }} - {{ render_field(form.tags, class_="selectize-default") }} {{ render_field(form.ansible_vars) }} {{ render_field(form.ansible_groups, class_="selectize-default") }} <div class="form-group row"> diff --git a/app/templates/network/create_interface.html b/app/templates/network/create_interface.html index a7ebe51ff2578f965a82be2554d1699a886f7af6..160668f19f91cc1a14241018ba6e99797c00bef5 100644 --- a/app/templates/network/create_interface.html +++ b/app/templates/network/create_interface.html @@ -26,7 +26,6 @@ {{ render_field(form.random_mac) }} {{ render_field(form.mac) }} {{ render_field(form.cnames_string) }} - {{ render_field(form.tags, class_="selectize-default") }} <div class="form-group row"> <div class="col-sm-10"> <button type="submit" class="btn btn-primary">Submit</button> diff --git a/app/templates/network/edit_host.html b/app/templates/network/edit_host.html index 3875ffe96dd07db363bd7effdeba11f4b30f8e09..f6f0bc1f556d247b29bc8133e60e79da39fa1f0b 100644 --- a/app/templates/network/edit_host.html +++ b/app/templates/network/edit_host.html @@ -20,6 +20,7 @@ {{ form.hidden_tag() }} {{ render_field(form.name, class_="text-lowercase") }} {{ render_field(form.device_type_id, class_="selectize-default") }} + {{ render_field(form.is_ioc) }} {{ render_field(form.description) }} {{ render_field(form.ansible_vars) }} {{ render_field(form.ansible_groups, class_="selectize-default") }} diff --git a/app/templates/network/edit_interface.html b/app/templates/network/edit_interface.html index 19ba2d8aed9fc28ee979a2230b36781911bbd4f3..cd751dfd0b561d88a393c8ef9e2eacb8e47c7191 100644 --- a/app/templates/network/edit_interface.html +++ b/app/templates/network/edit_interface.html @@ -28,7 +28,6 @@ {{ render_field(form.ip) }} {{ render_field(form.mac) }} {{ render_field(form.cnames_string) }} - {{ render_field(form.tags, class_="selectize-default") }} <div class="form-group row"> <div class="col-sm-10"> <button type="submit" class="btn btn-primary">Submit</button> diff --git a/app/templates/network/view_host.html b/app/templates/network/view_host.html index a1dda629ba7cf27828dbaf15c6e86e6e65855f45..52705debf17257c27d2c55c1b9059b08a2d7cff7 100644 --- a/app/templates/network/view_host.html +++ b/app/templates/network/view_host.html @@ -40,6 +40,8 @@ </dd> <dt class="col-sm-3">Device Type</dt> <dd class="col-sm-9">{{ host.device_type }}</dd> + <dt class="col-sm-3">IOC</dt> + <dd class="col-sm-9">{{ host.is_ioc }}</dd> {% if host.items %} <dt class="col-sm-3">Items</dt> <dd class="col-sm-9">{{ link_to_items(host.items) }}</dd> @@ -101,7 +103,6 @@ <th>IP</th> <th>MAC</th> <th>Network</th> - <th>Tags</th> </tr> </thead> <tbody> @@ -122,7 +123,6 @@ <td>{{ interface.ip }}</td> <td>{{ interface.mac }}</td> <td>{{ link_to_network(interface.network) }}</td> - <td>{{ interface.tags | join(' ') }}</td> </tr> {% endfor %} </tbody> diff --git a/app/validators.py b/app/validators.py index 575bc87e6e87f9a48881a9cf8f13c27fe1024593..2e7f8f48f1fe2915b40ba7b68248c769d0b5f028 100644 --- a/app/validators.py +++ b/app/validators.py @@ -19,7 +19,6 @@ HOST_NAME_RE = re.compile("^[a-z0-9\-]{2,20}$") VLAN_NAME_RE = re.compile("^[A-Za-z0-9\-]{3,25}$") MAC_ADDRESS_RE = re.compile("^(?:[0-9a-fA-F]{2}[:-]?){5}[0-9a-fA-F]{2}$") DEVICE_TYPE_RE = re.compile("^[A-Za-z0-9]{3,25}$") -TAG_RE = DEVICE_TYPE_RE class NoValidateSelectField(SelectField): diff --git a/docs/_static/create_vioc.png b/docs/_static/create_vioc.png index c7878ba683e67765734f2ff4fa6e9de6c2891631..a0d25727887dff5098832992539ddd6bfdb5ea14 100644 Binary files a/docs/_static/create_vioc.png and b/docs/_static/create_vioc.png differ diff --git a/docs/_static/create_vm.png b/docs/_static/create_vm.png index 16033163b3bcb4054e3327e1cda5a1a78cb2e8e4..9eeefdf59d035977d1396411044bb7c8c9a2889a 100644 Binary files a/docs/_static/create_vm.png and b/docs/_static/create_vm.png differ diff --git a/docs/_static/register_host.png b/docs/_static/register_host.png index e7feab21ce44588dea4ec6b0b0f928229aa1b423..252d24cb84f6c7f50c774a3adad1b9caa3a092df 100644 Binary files a/docs/_static/register_host.png and b/docs/_static/register_host.png differ diff --git a/docs/network.rst b/docs/network.rst index 78cbb2c7b5cb7049abd92c6f76892114d631d082..656bd9f0af9bbe6a9516d5fb47a2bb59666eeb74 100644 --- a/docs/network.rst +++ b/docs/network.rst @@ -81,11 +81,11 @@ To register a new host, you should: 1. Enter a hostname. 2. Choose a Type. For physical machines, you can associate an **item** from the inventory (optional). - 3. Enter a description (optional). - 4. Choose the network for the primary interface. The first available IP address on that network is automatically filled. + 3. If the host is an IOC, select the **IOC** checkbox. + 4. Enter a description. + 5. Choose the network for the primary interface. The first available IP address on that network is automatically filled. You should not modify it except if you have a specific reason. - 5. For physical machines, you have to enter the MAC address. A random one is automatically generated for virtual machines. - 6. If the host is an IOC, you should select the **IOC** tag. It should be selected by default depending on the device type. Unselect it otherwise. + 6. For physical machines, you have to enter the MAC address. A random one is automatically generated for virtual machines. 7. Click Submit. .. image:: _static/register_host.png @@ -129,7 +129,7 @@ From the *View host* page, you can trigger the creation of a Virtual machine: .. image:: _static/create_vm.png -If the host is an IOC (the interface should have the **IOC** tag), the form will be slightly different: +If the host is an IOC, the form will be slightly different: .. image:: _static/create_vioc.png diff --git a/migrations/versions/ac04850e5f68_add_is_ioc_field.py b/migrations/versions/ac04850e5f68_add_is_ioc_field.py new file mode 100644 index 0000000000000000000000000000000000000000..e9bc161ac26b822bd885654f1341a796bedc902a --- /dev/null +++ b/migrations/versions/ac04850e5f68_add_is_ioc_field.py @@ -0,0 +1,76 @@ +"""Add is_ioc field + +Revision ID: ac04850e5f68 +Revises: f7d72e432f51 +Create Date: 2019-02-28 11:28:36.993953 + +""" +from alembic import op +import sqlalchemy as sa +import citext + + +# revision identifiers, used by Alembic. +revision = "ac04850e5f68" +down_revision = "f7d72e432f51" +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute("COMMIT") + op.execute("ALTER TYPE ansible_group_type ADD VALUE 'IOC'") + op.add_column( + "host", + sa.Column("is_ioc", sa.Boolean(), nullable=False, server_default="False"), + ) + op.add_column( + "host_version", + sa.Column("is_ioc", sa.Boolean(), autoincrement=False, nullable=True), + ) + host = sa.sql.table("host", sa.sql.column("id"), sa.sql.column("is_ioc")) + conn = op.get_bind() + res = conn.execute("SELECT id FROM tag WHERE name = 'IOC';") + row = res.fetchone() + ioc_tag_id = row[0] + res.close() + res = conn.execute( + f"""SELECT interface.host_id FROM interface + INNER JOIN interfacetags ON interface.id = interfacetags.interface_id + WHERE interfacetags.tag_id = {ioc_tag_id}; + """ + ) + results = res.fetchall() + for result in results: + op.execute(host.update().where(host.c.id == result[0]).values(is_ioc=True)) + op.drop_table("interfacetags") + op.drop_table("tag") + + +def downgrade(): + # WARNING! The downgrade doesn't recreate the IOC tag + op.drop_column("host_version", "is_ioc") + op.drop_column("host", "is_ioc") + op.create_table( + "tag", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("name", citext.CIText(), autoincrement=False, nullable=False), + sa.Column("description", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("admin_only", sa.BOOLEAN(), autoincrement=False, nullable=False), + sa.PrimaryKeyConstraint("id", name="pk_tag"), + sa.UniqueConstraint("name", name="uq_tag_name"), + ) + op.create_table( + "interfacetags", + sa.Column("tag_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column("interface_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.ForeignKeyConstraint( + ["interface_id"], + ["interface.id"], + name="fk_interfacetags_interface_id_interface", + ), + sa.ForeignKeyConstraint( + ["tag_id"], ["tag.id"], name="fk_interfacetags_tag_id_tag" + ), + sa.PrimaryKeyConstraint("tag_id", "interface_id", name="pk_interfacetags"), + ) diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 048817eaaec6af5c9b160d878331bf7942b0083f..3c57475a19ec34d2911b1472eec0958902f800f1 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -35,7 +35,6 @@ register(factories.HostFactory) register(factories.MacFactory) register(factories.DomainFactory) register(factories.CnameFactory) -register(factories.TagFactory) register(factories.TaskFactory) diff --git a/tests/functional/factories.py b/tests/functional/factories.py index 72fa05b748b5ed4102da790cef1312422b007b0b..be0c0e14a4b915ed128c392230c592e3c26dcfec 100644 --- a/tests/functional/factories.py +++ b/tests/functional/factories.py @@ -217,15 +217,6 @@ class CnameFactory(factory.alchemy.SQLAlchemyModelFactory): user = factory.SubFactory(UserFactory) -class TagFactory(factory.alchemy.SQLAlchemyModelFactory): - class Meta: - model = models.Tag - sqlalchemy_session = common.Session - sqlalchemy_session_persistence = "commit" - - name = factory.Sequence(lambda n: f"Tag{n}") - - class TaskFactory(factory.alchemy.SQLAlchemyModelFactory): class Meta: model = models.Task diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py index 294820165e8880b4f55fcad54a22d5f480dbb450..a6dfe5fab995f2af7af5c06a6a8ac437608c9ad1 100644 --- a/tests/functional/test_api.py +++ b/tests/functional/test_api.py @@ -74,7 +74,6 @@ INTERFACE_KEYS = { "device_type", "model", "cnames", - "tags", "created_at", "updated_at", "user", diff --git a/tests/functional/test_models.py b/tests/functional/test_models.py index 18b55dd5ee89d76b63b40bcc1773451f0def405f..b57ed01279cbfbe5fb06dedfe6d185f7fe6658f8 100644 --- a/tests/functional/test_models.py +++ b/tests/functional/test_models.py @@ -195,14 +195,6 @@ def test_device_type_validation(device_type_factory): assert "'Physical Machine' is an invalid device type name" in str(excinfo.value) -def test_tag_validation(tag_factory): - tag = tag_factory(name="IOC") - assert tag.name == "IOC" - with pytest.raises(ValidationError) as excinfo: - tag = tag_factory(name="My tag") - assert "'My tag' is an invalid tag name" in str(excinfo.value) - - def test_ansible_groups(ansible_group_factory, host_factory): group1 = ansible_group_factory() group2 = ansible_group_factory() @@ -222,6 +214,8 @@ def test_ansible_group_is_dynamic(ansible_group_factory): assert group2.is_dynamic group3 = ansible_group_factory(type=models.AnsibleGroupType.NETWORK) assert group3.is_dynamic + group4 = ansible_group_factory(type=models.AnsibleGroupType.IOC) + assert group4.is_dynamic def test_ansible_groups_children(ansible_group_factory, host_factory): @@ -327,6 +321,14 @@ def test_ansible_dynamic_network_scope_group( assert group3.hosts == [] +def test_ansible_dynamic_ioc_group(ansible_group_factory, host_factory): + host1 = host_factory(name="host1", is_ioc=True) + host2 = host_factory(name="host2", is_ioc=True) + host_factory(name="host3", is_ioc=False) + group = ansible_group_factory(name="iocs", type=models.AnsibleGroupType.IOC) + assert group.hosts == [host1, host2] + + @pytest.mark.parametrize("status", [None, "FINISHED", "FAILED", "STARTED"]) def test_no_task_waiting(status, user, task_factory): if status is None: @@ -488,16 +490,17 @@ def test_host_fqdn(host_factory, interface_factory): assert host1.fqdn == f"{host1.name}.{interface1.network.domain.name}" -def test_host_is_ioc(host_factory, interface_factory, tag_factory): - ioc_tag = tag_factory(name="IOC") - another_tag = tag_factory(name="foo") - host1 = host_factory() - interface_factory(name=host1.name, host=host1, tags=[ioc_tag]) - interface_factory(host=host1) +def test_host_is_ioc(host_factory, interface_factory): + host1 = host_factory(is_ioc=True) + interface1 = interface_factory(name=host1.name, host=host1) + interface2 = interface_factory(host=host1) assert host1.is_ioc + assert interface1.is_ioc + assert not interface2.is_ioc host2 = host_factory() - interface_factory(name=host2.name, host=host2, tags=[another_tag]) + interface3 = interface_factory(name=host2.name, host=host2) assert not host2.is_ioc + assert not interface3.is_ioc def test_cname_existing_host(db, host_factory, cname_factory): diff --git a/tests/functional/test_web.py b/tests/functional/test_web.py index 820a66744fe412f53a6581501d97aceecc51c181..f37dfe4305957cb184f1f1d85cf6107ef5d701bf 100644 --- a/tests/functional/test_web.py +++ b/tests/functional/test_web.py @@ -228,7 +228,7 @@ def test_retrieve_hosts(logged_client, interface_factory, host_factory): hosts = response.get_json()["data"] assert {host1.name, host2.name} == set(host["name"] for host in hosts) assert len(hosts[0]) == 14 - assert len(hosts[0]["interfaces"][0]) == 16 + assert len(hosts[0]["interfaces"][0]) == 15 def test_retrieve_hosts_by_ip(logged_client, interface_factory): @@ -307,12 +307,12 @@ def test_create_host(client, domain_factory, network_factory, device_type): "network_id": network.id, "name": name, "device_type_id": device_type.id, + "is_ioc": False, "ip": ip, "mac": mac, "description": "test", "ansible_vars": "", "ansible_groups": [], - "tags": [], "random_mac": False, "cnames_string": "", } @@ -356,12 +356,12 @@ def test_create_host_invalid_fields( "network_id": network.id, "name": name, "device_type_id": device_type.id, + "is_ioc": False, "ip": ip, "mac": mac, "description": "test", "ansible_vars": "", "ansible_groups": [], - "tags": [], "random_mac": False, "cnames_string": "", } @@ -409,7 +409,6 @@ def test_create_interface( "ip": ip, "mac": mac, "cnames_string": "", - "tags": [], } # Permission denied # user_lab doesn't have permissions for the host domain: prod.example.org