class LoadLNetJob(LNetStateChangeJob): state_transition = StateChangeJob.StateTransition(LNetConfiguration, "lnet_unloaded", "lnet_down") stateful_object = "lnet_configuration" lnet_configuration = models.ForeignKey(LNetConfiguration, on_delete=CASCADE) state_verb = "Load LNet" display_group = Job.JOB_GROUPS.COMMON display_order = 30 class Meta: app_label = "chroma_core" ordering = ["id"] @classmethod def long_description(cls, stateful_object): if stateful_object.is_managed: return help_text["load_lnet"] else: return help_text["Start monitoring LNet on %s"] % stateful_object.host def description(self): return self.long_description(self.lnet_configuration) def get_steps(self): fqdn = self.lnet_configuration.host.fqdn host_id = self.lnet_configuration.host.id return self.lnet_configuration.filter_steps( [ (LoadLNetStep, {"fqdn": fqdn}), (GetLNetStateStep, {"host_id": host_id, "fqdn": fqdn}), ] )
class RemoveLustreClientJob(StateChangeJob): """ Enables the client mount to be transitioned from unmounted -> removed as part of a dependency resolution phase. """ state_transition = StateChangeJob.StateTransition(LustreClientMount, "unmounted", "removed") stateful_object = "lustre_client_mount" lustre_client_mount = models.ForeignKey(LustreClientMount, on_delete=CASCADE) state_verb = None @classmethod def long_description(cls, stateful_object): return help_text["remove_lustre_client_mount"] def get_requires_confirmation(self): return True def get_confirmation_string(self): return RemoveLustreClientJob.long_description(None) def description(self): return "Remove %s" % self.lustre_client_mount def get_steps(self): return [(DeleteLustreClientMountStep, { "client_mount": self.lustre_client_mount })] class Meta: app_label = "chroma_core" ordering = ["id"]
class EnableLNetJob(NullStateChangeJob): target_object = models.ForeignKey(LNetConfiguration, on_delete=CASCADE) state_transition = StateChangeJob.StateTransition(LNetConfiguration, "unconfigured", "lnet_unloaded") class Meta: app_label = "chroma_core" ordering = ["id"] def description(self): return self.long_description(self.target_object) @classmethod def long_description(cls, stateful_object): if stateful_object.is_managed: return help_text["Enable LNet on %s"] % stateful_object.host else: return help_text["Start monitoring LNet on %s"] % stateful_object.host def get_deps(self): """ Before LNet operations are possible some dependencies are need, basically the host must have had its packages installed. Maybe we need a packages object, but this routine at least keeps the detail in one place. Or maybe we need an unacceptable_states lists. :return: """ if self.target_object.host.state in ["unconfigured", "undeployed"]: return DependOn(self.target_object.host, "packages_installed") else: return DependAll()
class StartCopytoolJob(StateChangeJob): state_transition = StateChangeJob.StateTransition(Copytool, "stopped", "started") copytool = models.ForeignKey(Copytool, on_delete=CASCADE) stateful_object = "copytool" state_verb = "Start" display_group = Job.JOB_GROUPS.COMMON display_order = 10 class Meta: app_label = "chroma_core" ordering = ["id"] @classmethod def get_args(cls, copytool): return {"copytool_id": copytool.pk} @classmethod def long_description(cls, stateful_object): return help_text["start_copytool"] def description(self): return "Start copytool %s on worker %s" % (self.copytool, self.copytool.host) def get_steps(self): return [(StartCopytoolStep, { "host": self.copytool.host, "copytool": self.copytool })]
class RemoveCopytoolJob(StateChangeJob): state_transition = StateChangeJob.StateTransition(Copytool, 'stopped', 'removed') copytool = models.ForeignKey(Copytool) stateful_object = 'copytool' state_verb = "Remove" display_group = Job.JOB_GROUPS.RARE display_order = 10 class Meta: app_label = 'chroma_core' ordering = ['id'] @classmethod def get_args(cls, copytool): return {'copytool_id': copytool.pk} @classmethod def long_description(cls, stateful_object): return help_text['remove_copytool'] def get_confirmation_string(self): return RemoveCopytoolJob.long_description(None) def get_requires_confirmation(self): return True def description(self): return "Remove copytool %s on worker %s" % (self.copytool, self.copytool.host) def get_steps(self): return [(CancelActiveOperationsStep, { 'copytool': self.copytool }), (StopCopytoolStep, { 'host': self.copytool.host, 'copytool': self.copytool }), (UnconfigureCopytoolStep, { 'host': self.copytool.host, 'copytool': self.copytool }), (DeleteCopytoolStep, { 'copytool': self.copytool })] def get_deps(self): search = lambda ct: ct.host == self.copytool.host copytools = ObjectCache.get(Copytool, search) # Only force an unmount if this is the only copytool associated # with the host. if len(copytools) == 1: search = lambda cm: cm.id == self.copytool.client_mount_id client_mount = ObjectCache.get_one(LustreClientMount, search) return DependOn(client_mount, 'unmounted') else: return DependAll()
class MountLustreClientJob(StateChangeJob): """ Enables the client mount to be transitioned from unmounted -> mounted as part of a dependency resolution phase. """ state_transition = StateChangeJob.StateTransition(LustreClientMount, "unmounted", "mounted") stateful_object = "lustre_client_mount" lustre_client_mount = models.ForeignKey(LustreClientMount, on_delete=CASCADE) state_verb = None @classmethod def long_description(cls, stateful_object): return help_text["mount_lustre_filesystem"] def get_confirmation_string(self): return MountLustreClientJob.long_description(None) def description(self): return "Mount %s" % self.lustre_client_mount def get_steps(self): host = ObjectCache.get_one( ManagedHost, lambda mh: mh.id == self.lustre_client_mount.host_id) mountpoint = (self.lustre_client_mount.mountpoints[0] if self.lustre_client_mount.mountpoints else "/mnt/{}".format(self.lustre_client_mount.filesystem)) filesystem = ObjectCache.get_one( ManagedFilesystem, lambda mf: mf.name == self.lustre_client_mount.filesystem) args = { "host": host, "filesystems": [(filesystem.mount_path(), mountpoint)] } return [(MountLustreFilesystemsStep, args)] def get_deps(self): return DependOn( ObjectCache.get_one( ManagedHost, lambda mh: mh.id == self.lustre_client_mount. host_id).lnet_configuration, "lnet_up", ) class Meta: app_label = "chroma_core" ordering = ["id"]
class RemoveUnconfiguredCopytoolJob(StateChangeJob): state_transition = StateChangeJob.StateTransition(Copytool, "unconfigured", "removed") copytool = models.ForeignKey(Copytool, on_delete=CASCADE) stateful_object = "copytool" state_verb = "Remove" display_group = Job.JOB_GROUPS.RARE display_order = 10 class Meta: app_label = "chroma_core" ordering = ["id"] @classmethod def get_args(cls, copytool): return {"copytool_id": copytool.pk} @classmethod def long_description(cls, stateful_object): return help_text["remove_copytool"] def get_confirmation_string(self): return RemoveUnconfiguredCopytoolJob.long_description(None) def get_requires_confirmation(self): return True def description(self): return "Remove copytool %s on worker %s" % (self.copytool, self.copytool.host) def get_steps(self): return [(DeleteCopytoolStep, {"copytool": self.copytool})] def get_deps(self): search = lambda ct: ct.host == self.copytool.host copytools = ObjectCache.get(Copytool, search) # Only force an unmount if this is the only copytool associated # with the host. if len(copytools) == 1: search = lambda cm: cm.id == self.copytool.client_mount_id client_mount = ObjectCache.get_one(LustreClientMount, search) return DependOn(client_mount, "unmounted") else: return DependAll()
class ForgetTargetJob(StateChangeJob): class Meta: app_label = "chroma_core" ordering = ["id"] @classmethod def long_description(cls, stateful_object): return select_description( stateful_object, { ManagedOst: help_text["remove_ost"], ManagedMdt: help_text["remove_mdt"], ManagedMgs: help_text["remove_mgt"], }, ) def description(self): modifier = "unmanaged" if self.target.immutable_state else "managed" return "Forget %s target %s" % (modifier, self.target) def get_requires_confirmation(self): return True def get_deps(self): deps = [] if issubclass(self.target.downcast_class, ManagedMgs): mgs = self.target.downcast() ticket = mgs.get_ticket() if ticket: deps.append( DependOn(ticket, "forgotten", fix_state=ticket.state)) return DependAll(deps) def on_success(self): _delete_target(self.target) super(ForgetTargetJob, self).on_success() state_transition = StateChangeJob.StateTransition(ManagedTarget, ["unmounted", "mounted"], "forgotten") stateful_object = "target" state_verb = "Forget" target = models.ForeignKey(ManagedTarget, on_delete=CASCADE)
class StopTargetJob(StateChangeJob): stateful_object = "target" state_transition = StateChangeJob.StateTransition(ManagedTarget, "mounted", "unmounted") state_verb = "Stop" target = models.ForeignKey(ManagedTarget, on_delete=CASCADE) def get_requires_confirmation(self): return True class Meta: app_label = "chroma_core" ordering = ["id"] @classmethod def long_description(cls, stateful_object): return select_description( stateful_object, { ManagedOst: help_text["stop_ost"], ManagedMgs: help_text["stop_mgt"], ManagedMdt: help_text["stop_mdt"] }, ) def description(self): return "Stop target %s" % self.target def get_deps(self): if issubclass(self.target.downcast_class, ManagedMgs): ticket = self.target.downcast().get_ticket() if ticket: return DependAll( DependOn(ticket, "revoked", fix_state="mounted")) return super(StopTargetJob, self).get_deps() def get_steps(self): return [ (UnmountStep, { "fqdn": self.target.best_available_host().fqdn, "ha_label": self.target.ha_label }), ]
class UnconfigureLNetJob(NullStateChangeJob): target_object = models.ForeignKey(LNetConfiguration, on_delete=CASCADE) state_transition = StateChangeJob.StateTransition(LNetConfiguration, "lnet_unloaded", "unconfigured") class Meta: app_label = "chroma_core" ordering = ["id"] def description(self): return self.long_description(self.target_object) @classmethod def long_description(cls, stateful_object): if stateful_object.is_managed: return help_text["Change lnet state of %s to unconfigured"] % stateful_object.host else: return help_text["Stop monitoring lnet on %s"] % stateful_object.host def get_steps(self): return self.target_object.filter_steps([(UnconfigureLNetStep, {"fqdn": self.target_object.host.fqdn})])
class StopCopytoolJob(StateChangeJob): state_transition = StateChangeJob.StateTransition(Copytool, 'started', 'stopped') copytool = models.ForeignKey(Copytool) stateful_object = 'copytool' state_verb = "Stop" display_group = Job.JOB_GROUPS.COMMON display_order = 10 class Meta: app_label = 'chroma_core' ordering = ['id'] @classmethod def get_args(cls, copytool): return {'copytool_id': copytool.pk} @classmethod def long_description(cls, stateful_object): return help_text['stop_copytool'] def get_confirmation_string(self): return StopCopytoolJob.long_description(None) def get_requires_confirmation(self): return True def description(self): return "Stop copytool %s on worker %s" % (self.copytool, self.copytool.host) def get_steps(self): return [(CancelActiveOperationsStep, { 'copytool': self.copytool }), (StopCopytoolStep, { 'host': self.copytool.host, 'copytool': self.copytool })]
class StartTargetJob(StateChangeJob): stateful_object = "target" state_transition = StateChangeJob.StateTransition(ManagedTarget, "unmounted", "mounted") state_verb = "Start" target = models.ForeignKey(ManagedTarget, on_delete=CASCADE) class Meta: app_label = "chroma_core" ordering = ["id"] @classmethod def long_description(cls, stateful_object): return select_description( stateful_object, { ManagedOst: help_text["start_ost"], ManagedMgs: help_text["start_mgt"], ManagedMdt: help_text["start_mdt"], }, ) def description(self): return "Start target %s" % self.target def get_deps(self): if issubclass(self.target.downcast_class, ManagedMgs): ticket = self.target.downcast().get_ticket() if ticket: return DependAll( DependOn(ticket, "granted", fix_state="unmounted")) if self.target.downcast_class in [ManagedMdt, ManagedOst]: from chroma_core.models import FilesystemTicket target = self.target.downcast() ticket = FilesystemTicket.objects.filter( filesystem=target.filesystem_id).first() if ticket: return DependAll( DependOn(ticket.ticket, "granted", fix_state="unmounted")) deps = [] # Depend on at least one targetmount having lnet up for host in self.target.hosts: from chroma_core.models import LNetConfiguration lnet_configuration = ObjectCache.get_one( LNetConfiguration, lambda l: l.host_id == host.id) deps.append( DependOn(lnet_configuration, "lnet_up", fix_state="unmounted")) try: pacemaker_configuration = ObjectCache.get_one( PacemakerConfiguration, lambda pm: pm.host_id == host.id) deps.append( DependOn(pacemaker_configuration, "started", fix_state="unmounted")) except PacemakerConfiguration.DoesNotExist: pass return DependAny(deps) def get_steps(self): return [(MountStep, { "fqdn": self.target.best_available_host().fqdn, "ha_label": self.target.ha_label })]