diff --git a/inv/models/sensorprofile.py b/inv/models/sensorprofile.py index 87af730a995810850337bd088318d73d89c369cc..e1998580bd0178be4f1597705b7cc31076691b6d 100644 --- a/inv/models/sensorprofile.py +++ b/inv/models/sensorprofile.py @@ -8,6 +8,7 @@ # NOC modules from threading import Lock import operator +from functools import partial # Third-party modules from mongoengine.document import Document, EmbeddedDocument @@ -51,7 +52,9 @@ class SensorProfile(Document): name = StringField(unique=True) description = StringField() - workflow = PlainReferenceField(Workflow) + workflow = PlainReferenceField( + Workflow, default=partial(Workflow.get_default_workflow, "inv.SensorProfile") + ) style = ForeignKeyField(Style) enable_collect = BooleanField(default=False) collect_interval = IntField(default=60) diff --git a/pm/models/agentprofile.py b/pm/models/agentprofile.py index ebb5832d12ee8c328f046c3b9dd9bf466e4824f5..bfd2c0a50cd83b8f6be6b77cfbf169db2d157b4e 100644 --- a/pm/models/agentprofile.py +++ b/pm/models/agentprofile.py @@ -8,6 +8,7 @@ # Python modules import operator from threading import Lock +from functools import partial # Third-party modules from mongoengine.document import Document @@ -28,15 +29,17 @@ class AgentProfile(Document): name = StringField(unique=True) description = StringField() - zk_check_interval = IntField() - workflow = PlainReferenceField(Workflow) + zk_check_interval = IntField(default=60) + workflow = PlainReferenceField( + Workflow, default=partial(Workflow.get_default_workflow, "pm.AgentProfile") + ) update_addresses = BooleanField(default=True) _id_cache = cachetools.TTLCache(maxsize=100, ttl=60) _default_cache = cachetools.TTLCache(maxsize=100, ttl=60) DEFAULT_PROFILE_NAME = "default" - DEFAULT_WORKFLOW_NAME = "Default" + DEFAULT_WORKFLOW_NAME = "Agent Default" def __str__(self): return self.name diff --git a/sa/models/serviceprofile.py b/sa/models/serviceprofile.py index 1de75b1edb701d5a6582eb13c0d14149c4a44371..da9bd5118fa413d25137c4f2146d4f6f5d2e4d87 100644 --- a/sa/models/serviceprofile.py +++ b/sa/models/serviceprofile.py @@ -8,6 +8,7 @@ # Python modules import operator from threading import Lock +from functools import partial # Third-party modules from pymongo import UpdateOne @@ -60,7 +61,9 @@ class ServiceProfile(Document): display_order = IntField(default=100) # Show in total summary show_in_summary = BooleanField(default=True) - workflow = PlainReferenceField(Workflow) + workflow = PlainReferenceField( + Workflow, default=partial(Workflow.get_default_workflow, "sa.ServiceProfile") + ) # Auto-assign interface profile when service binds to interface interface_profile = ReferenceField(InterfaceProfile) # Alarm weight @@ -80,6 +83,9 @@ class ServiceProfile(Document): _id_cache = cachetools.TTLCache(maxsize=100, ttl=60) + DEFAULT_PROFILE_NAME = "default" + DEFAULT_WORKFLOW_NAME = "Service Default" + def __str__(self): return self.name diff --git a/sla/models/slaprofile.py b/sla/models/slaprofile.py index 5ba09ca2c5089a15c7b0e76bc72467db58cd02fd..b5f9ba79213fb11502e9eff4d7ca5e6ea0eb75ff 100644 --- a/sla/models/slaprofile.py +++ b/sla/models/slaprofile.py @@ -8,6 +8,7 @@ # Python modules from threading import Lock import operator +from functools import partial # Third-party modules from mongoengine.document import Document, EmbeddedDocument @@ -59,7 +60,9 @@ class SLAProfile(Document): name = StringField(unique=True) description = StringField() # - workflow = PlainReferenceField(Workflow) + workflow = PlainReferenceField( + Workflow, default=partial(Workflow.get_default_workflow, "sla.SLAProfile") + ) style = ForeignKeyField(Style, required=False) # Agent collected intervale collect_interval = IntField(default=120) diff --git a/ui/web/inv/sensorprofile/Application.js b/ui/web/inv/sensorprofile/Application.js index 12bc8409ce53846ae36a2cc327e51ee2787c3467..4b1c3a3dfc0386dba3e7c5717ad097d63b14052b 100644 --- a/ui/web/inv/sensorprofile/Application.js +++ b/ui/web/inv/sensorprofile/Application.js @@ -57,7 +57,7 @@ Ext.define("NOC.inv.sensorprofile.Application", { name: "workflow", xtype: "wf.workflow.LookupField", fieldLabel: __("WorkFlow"), - allowBlank: false + allowBlank: true }, { name: "style", diff --git a/ui/web/pm/agentprofile/Application.js b/ui/web/pm/agentprofile/Application.js index 08534456970be1bacefbca459dcfdcff2fade206..bd7419ce29a313a40a3083bca4bfc75423986831 100644 --- a/ui/web/pm/agentprofile/Application.js +++ b/ui/web/pm/agentprofile/Application.js @@ -63,7 +63,7 @@ Ext.define("NOC.pm.agentprofile.Application", { name: "workflow", xtype: "wf.workflow.LookupField", fieldLabel: __("Workflow"), - allowBlank: false + allowBlank: true } ] }); diff --git a/ui/web/sla/slaprofile/Application.js b/ui/web/sla/slaprofile/Application.js index d99064fdc6adf514b6806ec9b0d8472000d2ab2b..1cd76f5e01c54fd1f70dd04a4ca3e17db8b0285e 100644 --- a/ui/web/sla/slaprofile/Application.js +++ b/ui/web/sla/slaprofile/Application.js @@ -56,7 +56,7 @@ Ext.define("NOC.sla.slaprofile.Application", { name: "workflow", xtype: "wf.workflow.LookupField", fieldLabel: __("WorkFlow"), - allowBlank: false + allowBlank: true }, { name: "style", diff --git a/wf/migrations/0012_agent_default.py b/wf/migrations/0012_agent_default.py new file mode 100644 index 0000000000000000000000000000000000000000..0f16b34432b98467572c6ab35a50b00921b6901a --- /dev/null +++ b/wf/migrations/0012_agent_default.py @@ -0,0 +1,196 @@ +# ---------------------------------------------------------------------- +# Agent Default workflow +# ---------------------------------------------------------------------- +# Copyright (C) 2007-2020 The NOC Project +# See LICENSE for details +# ---------------------------------------------------------------------- + +# Third-party modules +from bson import ObjectId + +# NOC modules +from noc.core.migration.base import BaseMigration + + +class Migration(BaseMigration): + def migrate(self): + db = self.mongo_db + # Workflow + db["workflows"].insert_one( + { + "_id": ObjectId("610bcff0902971a3863306fb"), + "name": "Agent Default", + "is_active": True, + "description": "Agent Default Workflow", + "bi_id": 3468966898630074545, + } + ) + # State + db["states"].insert_many( + [ + { + "_id": ObjectId("610be4c771b6da38e5f5acb2"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "name": "Approved", + "description": "Agent is approved for ready", + "is_default": False, + "is_productive": False, + "update_last_seen": False, + "ttl": 0, + "update_expired": False, + "on_enter_handlers": [], + "on_leave_handlers": [], + "x": 260, + "y": 50, + "labels": ["noc::agent::auth::pre"], + "effective_labels": ["noc::agent::auth::pre"], + "bi_id": 3373553393116727828, + }, + { + "_id": ObjectId("610be3c671b6da38e5f5acb0"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "name": "New", + "description": "New registered agent on System", + "is_default": True, + "is_productive": False, + "update_last_seen": False, + "ttl": 0, + "update_expired": False, + "on_enter_handlers": [], + "on_leave_handlers": [], + "x": 50, + "y": 50, + "labels": ["noc::agent::auth::none"], + "effective_labels": ["noc::agent::auth::none"], + "bi_id": 6693212396144621794, + }, + { + "_id": ObjectId("610bd09371b6da38e5f5acae"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "name": "Ready", + "description": "Agent is in productive usage", + "is_default": False, + "is_productive": True, + "update_last_seen": True, + "ttl": 0, + "update_expired": False, + "on_enter_handlers": [], + "on_leave_handlers": [], + "x": 260, + "y": 200, + "labels": ["noc::agent::auth::auth"], + "effective_labels": ["noc::agent::auth::auth"], + "bi_id": 6323558026723790432, + }, + { + "_id": ObjectId("610be4fd902971a3863306ff"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "name": "Removing", + "description": "Agent is removed from system use", + "is_default": False, + "is_productive": False, + "update_last_seen": False, + "ttl": 0, + "update_expired": False, + "on_enter_handlers": [], + "on_leave_handlers": [], + "x": 350, + "y": 370, + "labels": ["noc::agent::auth::none"], + "effective_labels": ["noc::agent::auth::none"], + "bi_id": 5644536921567111119, + }, + { + "_id": ObjectId("610be4d9902971a3863306fd"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "name": "Suspended", + "description": "Agent is temporary suspended/blocked for organisational reasons", + "is_default": False, + "is_productive": False, + "update_last_seen": False, + "ttl": 0, + "update_expired": False, + "on_enter_handlers": [], + "on_leave_handlers": [], + "x": 140, + "y": 300, + "labels": ["noc::agent::auth::pre"], + "effective_labels": ["noc::agent::auth::pre"], + "bi_id": 7418372945801511030, + }, + ] + ) + # Transitions + db["transitions"].insert_many( + [ + { + "_id": ObjectId("610be699902971a386330701"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "from_state": ObjectId("610be4c771b6da38e5f5acb2"), + "to_state": ObjectId("610bd09371b6da38e5f5acae"), + "is_active": True, + "event": "seen", + "label": "Seen", + "enable_manual": True, + "handlers": [], + "vertices": [], + "bi_id": 2789875778847456366, + "description": "", + }, + { + "_id": ObjectId("610be6b471b6da38e5f5acb5"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "from_state": ObjectId("610bd09371b6da38e5f5acae"), + "to_state": ObjectId("610be4d9902971a3863306fd"), + "is_active": True, + "event": "suspend", + "label": "Suspend", + "enable_manual": True, + "handlers": [], + "vertices": [], + "bi_id": 7385490058000949812, + "description": "", + }, + { + "_id": ObjectId("610be6c771b6da38e5f5acb7"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "from_state": ObjectId("610be4d9902971a3863306fd"), + "to_state": ObjectId("610bd09371b6da38e5f5acae"), + "is_active": True, + "event": "resume", + "label": "Resume", + "enable_manual": True, + "handlers": [], + "vertices": [], + "bi_id": 3738440408351158595, + "description": "", + }, + { + "_id": ObjectId("610be6f871b6da38e5f5acb9"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "from_state": ObjectId("610be4d9902971a3863306fd"), + "to_state": ObjectId("610be4fd902971a3863306ff"), + "is_active": True, + "label": "Remove", + "enable_manual": True, + "handlers": [], + "vertices": [], + "bi_id": 6195769163155286672, + "description": "", + }, + { + "_id": ObjectId("610be76671b6da38e5f5acbb"), + "workflow": ObjectId("610bcff0902971a3863306fb"), + "from_state": ObjectId("610be3c671b6da38e5f5acb0"), + "to_state": ObjectId("610be4c771b6da38e5f5acb2"), + "is_active": True, + "event": "approve", + "label": "Approve", + "enable_manual": True, + "handlers": [], + "vertices": [], + "bi_id": 8807158971147672185, + "description": "", + }, + ] + ) diff --git a/wf/models/workflow.py b/wf/models/workflow.py index 1438a07de19d885c0bc0027e7742f9a15f288390..c8ba65414cbfc403b91bbc85d8bd3283fbf8181f 100644 --- a/wf/models/workflow.py +++ b/wf/models/workflow.py @@ -9,6 +9,7 @@ from threading import Lock import operator import logging +from typing import Optional # Third-party modules from mongoengine.document import Document @@ -59,22 +60,38 @@ class Workflow(Document): # Object id in BI bi_id = LongField(unique=True) - _id_cache = cachetools.TTLCache(maxsize=1000, ttl=60) - _bi_id_cache = cachetools.TTLCache(maxsize=1000, ttl=60) + DEFAULT_WORKFLOW_NAME = "Default" + + _id_cache = cachetools.TTLCache(maxsize=100, ttl=60) + _name_cache = cachetools.TTLCache(maxsize=100, ttl=60) + _bi_id_cache = cachetools.TTLCache(maxsize=100, ttl=60) def __str__(self): return self.name @classmethod @cachetools.cachedmethod(operator.attrgetter("_id_cache"), lock=lambda _: id_lock) - def get_by_id(cls, id): + def get_by_id(cls, id) -> Optional["Workflow"]: return Workflow.objects.filter(id=id).first() @classmethod @cachetools.cachedmethod(operator.attrgetter("_bi_id_cache"), lock=lambda _: id_lock) - def get_by_bi_id(cls, id): + def get_by_bi_id(cls, id) -> Optional["Workflow"]: return Workflow.objects.filter(bi_id=id).first() + @classmethod + @cachetools.cachedmethod(operator.attrgetter("_name_cache"), lock=lambda _: id_lock) + def get_by_name(cls, name) -> Optional["Workflow"]: + return Workflow.objects.filter(name=name).first() + + @classmethod + def get_default_workflow(cls, model_id): + from noc.models import get_model + + model = get_model(model_id) + workflow = getattr(model, "DEFAULT_WORKFLOW_NAME", cls.DEFAULT_WORKFLOW_NAME) + return Workflow.get_by_name(workflow) + @cachetools.cached(_default_state_cache, key=lambda x: str(x.id), lock=id_lock) def get_default_state(self): from .state import State