using System; using System.Collections.Generic; using System.Linq; using System.Security.Permissions; using System.ServiceModel; using HeuristicLab.Services.Hive.Common; using HeuristicLab.Services.Hive.Common.DataTransfer; using HeuristicLab.Services.Hive.Common.ServiceContracts; namespace HeuristicLab.Services.Hive { /// /// Implementation of the Hive service (interface ). /// We need 'IgnoreExtensionDataObject' Attribute for the slave to work. /// [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IgnoreExtensionDataObject = true)] public class HiveService : IHiveService { private DataAccess.IHiveDao dao { get { return ServiceLocator.Instance.HiveDao; } } private HeuristicLab.Services.Hive.DataAccess.TransactionManager trans { get { return ServiceLocator.Instance.TransactionManager; } } private IAuthorizationManager auth { get { return ServiceLocator.Instance.AuthorizationManager; } } private ILifecycleManager lifecycleManager { get { return ServiceLocator.Instance.LifecycleManager; } } private HeartbeatManager heartbeatManager { get { return ServiceLocator.Instance.HeartbeatManager; } } #region Job Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid AddJob(Job job, JobData jobData, IEnumerable resourceIds) { return trans.UseTransaction(() => { job.Id = dao.AddJob(job); jobData.JobId = job.Id; jobData.LastUpdate = DateTime.Now; if (resourceIds != null) { foreach (Guid slaveGroupId in resourceIds) { dao.AssignJobToResource(job.Id, slaveGroupId); } } else { // todo: use default group } dao.AddJobData(jobData); dao.UpdateJobState(job.Id, JobState.Waiting, null, auth.UserId, null); return jobData.JobId; }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid AddChildJob(Guid parentJobId, Job job, JobData jobData) { return trans.UseTransaction(() => { job.ParentJobId = parentJobId; return AddJob(job, jobData, dao.GetAssignedResources(parentJobId).Select(x => x.Id)); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public Job GetJob(Guid jobId) { return dao.GetJob(jobId); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public IEnumerable GetJobs() { return dao.GetJobs(x => true); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public IEnumerable GetLightweightJobs(IEnumerable jobIds) { return dao.GetJobs(x => jobIds.Contains(x.JobId)).Select(x => new LightweightJob(x)).ToArray(); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public IEnumerable GetLightweightChildJobs(Guid? parentJobId, bool recursive, bool includeParent) { return GetChildJobs(parentJobId, recursive, includeParent).Select(x => new LightweightJob(x)).ToArray(); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public JobData GetJobData(Guid jobId) { return dao.GetJobData(jobId); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void UpdateJob(Job job) { trans.UseTransaction(() => { dao.UpdateJob(job); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void UpdateJobData(Job job, JobData jobData) { trans.UseTransaction(() => { jobData.LastUpdate = DateTime.Now; dao.UpdateJob(job); dao.UpdateJobData(jobData); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void DeleteJob(Guid jobId) { trans.UseTransaction(() => { dao.DeleteJob(jobId); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void DeleteChildJobs(Guid parentJobId) { trans.UseTransaction(() => { var jobs = GetChildJobs(parentJobId, true, false); foreach (var job in jobs) { dao.DeleteJob(job.Id); dao.DeleteJobData(job.Id); }; }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public Job UpdateJobState(Guid jobId, JobState jobState, Guid? slaveId, Guid? userId, string exception) { return trans.UseTransaction(() => { Job job = dao.UpdateJobState(jobId, jobState, slaveId, userId, exception); if (job.Command.HasValue && job.Command.Value == Command.Pause && job.State == JobState.Paused) { job.Command = null; } else if (job.Command.HasValue && job.Command.Value == Command.Abort && job.State == JobState.Aborted) { job.Command = null; } else if (job.Command.HasValue && job.Command.Value == Command.Stop && job.State == JobState.Aborted) { job.Command = null; } dao.UpdateJob(job); return job; }); } #endregion #region Job Control Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void StopJob(Guid jobId) { trans.UseTransaction(() => { //dao.UpdateJobState(jobId, JobState.Aborted, null, auth.UserId, string.Empty); var job = dao.GetJob(jobId); job.Command = Command.Stop; dao.UpdateJob(job); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void PauseJob(Guid jobId) { trans.UseTransaction(() => { //dao.UpdateJobState(jobId, JobState.Paused, null, auth.UserId, string.Empty); var job = dao.GetJob(jobId); job.Command = Command.Pause; dao.UpdateJob(job); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void RestartJob(Guid jobId) { trans.UseTransaction(() => { Job job = dao.UpdateJobState(jobId, JobState.Waiting, null, auth.UserId, string.Empty); job.Command = null; dao.UpdateJob(job); }); } #endregion #region HiveExperiment Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public HiveExperiment GetHiveExperiment(Guid id) { return dao.GetHiveExperiments(x => x.HiveExperimentId == id && (x.OwnerUserId == auth.UserId || x.HiveExperimentPermissions.Count(hep => hep.Permission != Permission.NotAllowed && hep.GrantedUserId == auth.UserId) > 0) ).FirstOrDefault(); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public IEnumerable GetHiveExperiments() { return dao.GetHiveExperiments(x => x.OwnerUserId == auth.UserId || x.HiveExperimentPermissions.Count(hep => hep.Permission != Permission.NotAllowed && hep.GrantedUserId == auth.UserId) > 0); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] public IEnumerable GetAllHiveExperiments() { return dao.GetHiveExperiments(x => true); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid AddHiveExperiment(HiveExperiment hiveExperimentDto) { return trans.UseTransaction(() => { hiveExperimentDto.OwnerUserId = auth.UserId; hiveExperimentDto.DateCreated = DateTime.Now; return dao.AddHiveExperiment(hiveExperimentDto); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void UpdateHiveExperiment(HiveExperiment hiveExperimentDto) { trans.UseTransaction(() => { dao.UpdateHiveExperiment(hiveExperimentDto); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void DeleteHiveExperiment(Guid hiveExperimentId) { trans.UseTransaction(() => { HiveExperiment he = dao.GetHiveExperiment(hiveExperimentId); dao.DeleteHiveExperiment(hiveExperimentId); // child jobs will be deleted by db-trigger }); } #endregion #region Login Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void Hello(Slave slaveInfo) { trans.UseTransaction(() => { var slave = dao.GetSlave(slaveInfo.Id); if (slave == null) { dao.AddSlave(slaveInfo); } else { dao.UpdateSlave(slaveInfo); } }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public void GoodBye(Guid slaveId) { trans.UseTransaction(() => { var slave = dao.GetSlave(slaveId); if (slave != null) { slave.SlaveState = SlaveState.Offline; dao.UpdateSlave(slave); } }); } #endregion #region Heartbeat Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public List Heartbeat(Heartbeat heartbeat) { TriggerLifecycle(false); return trans.UseTransaction(() => heartbeatManager.ProcessHeartbeat(heartbeat)); } #endregion #region Plugin Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid AddPlugin(Plugin plugin, List pluginDatas) { return trans.UseTransaction(() => { plugin.UserId = auth.UserId; plugin.DateCreated = DateTime.Now; Guid pluginId = dao.AddPlugin(plugin); foreach (PluginData pluginData in pluginDatas) { pluginData.PluginId = pluginId; dao.AddPluginData(pluginData); } return pluginId; }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public IEnumerable GetPlugins() { return dao.GetPlugins(x => x.IsLocal == false); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Slave)] public IEnumerable GetPluginDatas(List pluginIds) { List pluginDatas = new List(); return trans.UseTransaction(() => { foreach (Guid guid in pluginIds) { List pluginData = dao.GetPluginDatas(x => x.PluginId == guid).ToList(); if (pluginData != null) { pluginDatas.AddRange(pluginData); } else { //ignore ? } } return pluginDatas; }); } #endregion #region Slave Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid AddSlave(Slave slave) { return trans.UseTransaction(() => dao.AddSlave(slave)); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid AddSlaveGroup(SlaveGroup slaveGroup) { return trans.UseTransaction(() => dao.AddSlaveGroup(slaveGroup)); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Slave GetSlave(Guid slaveId) { return dao.GetSlave(slaveId); } public SlaveGroup GetSlaveGroup(Guid slaveGroupId) { return dao.GetSlaveGroup(slaveGroupId); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public IEnumerable GetSlaves() { return dao.GetSlaves(x => true); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public IEnumerable GetSlaveGroups() { return dao.GetSlaveGroups(x => true); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void UpdateSlave(Slave slave) { trans.UseTransaction(() => { dao.UpdateSlave(slave); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void UpdateSlaveGroup(SlaveGroup slaveGroup) { trans.UseTransaction(() => { dao.UpdateSlaveGroup(slaveGroup); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void DeleteSlave(Guid slaveId) { trans.UseTransaction(() => { dao.DeleteSlave(slaveId); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void DeleteSlaveGroup(Guid slaveGroupId) { trans.UseTransaction(() => { dao.DeleteSlaveGroup(slaveGroupId); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void AddResourceToGroup(Guid slaveGroupId, Guid resourceId) { trans.UseTransaction(() => { var resource = dao.GetResource(resourceId); resource.ParentResourceId = slaveGroupId; dao.UpdateResource(resource); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public void RemoveResourceFromGroup(Guid slaveGroupId, Guid resourceId) { trans.UseTransaction(() => { var resource = dao.GetResource(resourceId); resource.ParentResourceId = null; dao.UpdateResource(resource); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Client)] public Guid GetResourceId(string resourceName) { return trans.UseTransaction(() => { var resource = dao.GetResources(x => x.Name == resourceName).FirstOrDefault(); if (resource != null) { return resource.Id; } else { return Guid.Empty; } }); } public void TriggerLifecycle(bool force) { trans.UseTransaction(() => { DateTime lastCleanup = dao.GetLastCleanup(); if (force || DateTime.Now - lastCleanup > TimeSpan.FromSeconds(59)) { dao.SetLastCleanup(DateTime.Now); lifecycleManager.Cleanup(); } }); } #endregion #region Helper Methods private IEnumerable GetChildJobs(Guid? parentJobId, bool recursive, bool includeParent) { var jobs = new List(dao.GetJobs(x => parentJobId == null ? !x.ParentJobId.HasValue : x.ParentJobId.Value == parentJobId)); if (recursive) { var childs = new List(); foreach (var job in jobs) { childs.AddRange(GetChildJobs(job.Id, recursive, false)); } jobs.AddRange(childs); } if (includeParent) jobs.Add(GetJob(parentJobId.Value)); return jobs; } #endregion #region Appointment Methods [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] public Guid AddAppointment(Appointment appointment) { return trans.UseTransaction(() => dao.AddAppointment(appointment)); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] public void DeleteAppointment(Guid appointmentId) { trans.UseTransaction(() => { dao.DeleteAppointment(appointmentId); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] public void UpdateAppointment(Appointment appointment) { trans.UseTransaction(() => { dao.UpdateAppointment(appointment); }); } [PrincipalPermission(SecurityAction.Demand, Role = HiveRoles.Administrator)] public IEnumerable GetScheduleForResource(Guid resourceId) { return trans.UseTransaction(() => dao.GetAppointments(x => x.ResourceId == resourceId)); } #endregion } }