Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3026_IntegrationIntoSymSpace/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs @ 18242

Last change on this file since 18242 was 17928, checked in by dpiringe, 4 years ago

#3026

  • merged trunk into branch
File size: 22.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Threading;
26using HeuristicLab.Clients.Access;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29
30namespace HeuristicLab.Clients.Hive {
31  [Item("Hive Administrator", "Hive Administrator")]
32  public sealed class HiveAdminClient : IContent {
33    private static HiveAdminClient instance;
34    public static HiveAdminClient Instance {
35      get {
36        if (instance == null) instance = new HiveAdminClient();
37        return instance;
38      }
39    }
40
41    #region Properties
42    private IItemList<Resource> resources;
43    public IItemList<Resource> Resources {
44      get { return resources; }
45    }
46
47    private IItemList<Downtime> downtimes;
48    public IItemList<Downtime> Downtimes {
49      get { return downtimes; }
50    }
51
52    private Guid downtimeForResourceId;
53    public Guid DowntimeForResourceId {
54      get { return downtimeForResourceId; }
55      set {
56        downtimeForResourceId = value;
57        if (downtimes != null) {
58          downtimes.Clear();
59        }
60      }
61    }
62
63    private IItemList<Project> projects;
64    public IItemList<Project> Projects {
65      get { return projects; }
66    }
67
68    private IItemList<AssignedProjectResource> projectResourceAssignments;
69    public IItemList<AssignedProjectResource> ProjectResourceAssignments {
70      get { return projectResourceAssignments; }
71    }
72
73    private Dictionary<Guid, HiveItemCollection<RefreshableJob>> jobs;
74    public Dictionary<Guid, HiveItemCollection<RefreshableJob>> Jobs {
75      get { return jobs; }
76      set {
77        if (value != jobs)
78          jobs = value;
79      }
80    }
81
82    private Dictionary<Guid, List<LightweightTask>> tasks;
83    public Dictionary<Guid, List<LightweightTask>> Tasks {
84      get { return tasks; }
85    }
86
87    private Dictionary<Guid, HashSet<Guid>> projectAncestors;
88    public Dictionary<Guid, HashSet<Guid>> ProjectAncestors {
89      get { return projectAncestors; }
90    }
91
92    private Dictionary<Guid, HashSet<Guid>> projectDescendants;
93    public Dictionary<Guid, HashSet<Guid>> ProjectDescendants {
94      get { return projectDescendants; }
95    }
96
97    private Dictionary<Guid, HashSet<Guid>> resourceAncestors;
98    public Dictionary<Guid, HashSet<Guid>> ResourceAncestors {
99      get { return resourceAncestors; }
100    }
101
102    private Dictionary<Guid, HashSet<Guid>> resourceDescendants;
103    public Dictionary<Guid, HashSet<Guid>> ResourceDescendants {
104      get { return resourceDescendants; }
105    }
106
107    private Dictionary<Guid, string> projectNames;
108    public Dictionary<Guid, string> ProjectNames {
109      get { return projectNames; }
110    }
111
112    private HashSet<Project> disabledParentProjects;
113    public HashSet<Project> DisabledParentProjects {
114      get { return disabledParentProjects; }
115    }
116
117    private Dictionary<Guid, string> resourceNames;
118    public Dictionary<Guid, string> ResourceNames {
119      get { return resourceNames; }
120    }
121
122    private HashSet<Resource> disabledParentResources;
123    public HashSet<Resource> DisabledParentResources {
124      get { return disabledParentResources; }
125    }
126    #endregion
127
128    #region Events
129    public event EventHandler Refreshing;
130    private void OnRefreshing() {
131      EventHandler handler = Refreshing;
132      if (handler != null) handler(this, EventArgs.Empty);
133    }
134    public event EventHandler Refreshed;
135    private void OnRefreshed() {
136      var handler = Refreshed;
137      if (handler != null) handler(this, EventArgs.Empty);
138    }
139    #endregion
140
141    private HiveAdminClient() { }
142
143    #region Refresh
144    public void Refresh() {
145      OnRefreshing();
146
147      try {
148        resources = new ItemList<Resource>();
149        projects = new ItemList<Project>();
150        projectResourceAssignments = new ItemList<AssignedProjectResource>();
151        jobs = new Dictionary<Guid, HiveItemCollection<RefreshableJob>>();
152        tasks = new Dictionary<Guid, List<LightweightTask>>();
153        projectNames = new Dictionary<Guid, string>();
154        resourceNames = new Dictionary<Guid, string>();
155
156        projectAncestors = new Dictionary<Guid, HashSet<Guid>>();
157        projectDescendants = new Dictionary<Guid, HashSet<Guid>>();
158        resourceAncestors = new Dictionary<Guid, HashSet<Guid>>();
159        resourceDescendants = new Dictionary<Guid, HashSet<Guid>>();
160
161        HiveServiceLocator.Instance.CallHiveService(service => {
162          service.GetSlaveGroupsForAdministration().ForEach(g => resources.Add(g));
163          service.GetSlavesForAdministration().ForEach(s => resources.Add(s));
164          service.GetProjectsForAdministration().ForEach(p => projects.Add(p));
165          var projectIds = projects.Select(p => p.Id).ToList();
166          if (projectIds.Any()) {
167            service.GetAssignedResourcesForProjectsAdministration(projectIds)
168                   .ForEach(a => projectResourceAssignments.Add(a));
169
170            projectNames = service.GetProjectNames();
171            resourceNames = service.GetResourceNames();
172          }
173        });
174
175        UpdateResourceGenealogy();
176        UpdateProjectGenealogy();
177        RefreshDisabledParentProjects();
178        RefreshDisabledParentResources();
179      } catch {
180        throw;
181      } finally {
182        OnRefreshed();
183      }
184    }
185
186    private void UpdateResourceGenealogy() {
187      resourceAncestors.Clear();
188      resourceDescendants.Clear();
189
190      // fetch resource ancestor set
191      HiveServiceLocator.Instance.CallHiveService(service => {
192        var ra = service.GetResourceGenealogy();
193        ra.Keys.ToList().ForEach(k => resourceAncestors.Add(k, new HashSet<Guid>()));
194        resourceAncestors.Keys.ToList().ForEach(k => resourceAncestors[k].UnionWith(ra[k]));
195      });
196
197      // build resource descendant set
198      resourceAncestors.Keys.ToList().ForEach(k => resourceDescendants.Add(k, new HashSet<Guid>()));
199      foreach (var ra in resourceAncestors) {
200        foreach (var ancestor in ra.Value) {
201          resourceDescendants[ancestor].Add(ra.Key);
202        }
203      }
204    }
205
206    private void UpdateProjectGenealogy() {
207      projectAncestors.Clear();
208      projectDescendants.Clear();
209
210      // fetch project ancestor list
211      HiveServiceLocator.Instance.CallHiveService(service => {
212        var pa = service.GetProjectGenealogy();
213        pa.Keys.ToList().ForEach(k => projectAncestors.Add(k, new HashSet<Guid>()));
214        projectAncestors.Keys.ToList().ForEach(k => projectAncestors[k].UnionWith(pa[k]));
215      });
216
217      // build project descendant list
218      projectAncestors.Keys.ToList().ForEach(k => projectDescendants.Add(k, new HashSet<Guid>()));
219      foreach (var pa in projectAncestors) {
220        foreach (var ancestor in pa.Value) {
221          projectDescendants[ancestor].Add(pa.Key);
222        }
223      }
224    }
225
226    private void RefreshDisabledParentProjects() {
227      disabledParentProjects = new HashSet<Project>();
228
229      foreach (var pid in projects
230        .Where(x => x.ParentProjectId.HasValue)
231        .SelectMany(x => projectAncestors[x.Id]).Distinct()
232        .Where(x => !projects.Select(y => y.Id).Contains(x))) {
233        var p = new Project();
234        p.Id = pid;
235        p.ParentProjectId = projectAncestors[pid].FirstOrDefault();
236        p.Name = projectNames[pid];
237        disabledParentProjects.Add(p);
238      }
239    }
240
241    private void RefreshDisabledParentResources() {
242      disabledParentResources = new HashSet<Resource>();
243
244      foreach (var rid in resources
245        .Where(x => x.ParentResourceId.HasValue)
246        .SelectMany(x => resourceAncestors[x.Id]).Distinct()
247        .Where(x => !resources.Select(y => y.Id).Contains(x))) {
248        var r = new SlaveGroup();
249        r.Id = rid;
250        r.ParentResourceId = resourceAncestors[rid].FirstOrDefault();
251        r.Name = resourceNames[rid];
252        disabledParentResources.Add(r);
253      }
254    }
255
256    public void RefreshJobs(Guid projectId) {
257      HiveServiceLocator.Instance.CallHiveService(service => {
258        var projectIds = new HashSet<Guid>(service.GetProjectsForAdministration().Select(x => x.Id));
259        if (projectIds.Contains(projectId)) {
260          jobs.Add(projectId, new HiveItemCollection<RefreshableJob>());
261
262          var unsortedJobs = service.GetJobsByProjectId(projectId)
263                                    .OrderBy(x => x.DateCreated).ToList();
264
265          unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
266          unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
267          unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
268
269          foreach (var job in jobs.SelectMany(x => x.Value))
270            LoadLightweightJob(job);
271        }
272      });
273    }
274
275    public void LoadLightweightJob(RefreshableJob refreshableJob) {
276      var job = refreshableJob.Job;
277      var lightweightTasks = HiveServiceLocator.Instance.CallHiveService(s => s.GetLightweightJobTasksWithoutStateLog(job.Id));
278
279      if (tasks.ContainsKey(job.Id)) {
280        tasks[job.Id].Clear();
281        tasks[job.Id].AddRange(lightweightTasks);
282      } else {
283        tasks.Add(job.Id, new List<LightweightTask>(lightweightTasks));
284      }
285
286      if (lightweightTasks != null && lightweightTasks.Count > 0 && lightweightTasks.All(x => x.Id != Guid.Empty)) {
287        if (lightweightTasks.All(x =>
288          x.State == TaskState.Finished
289          || x.State == TaskState.Aborted
290          || x.State == TaskState.Failed)) {
291          refreshableJob.ExecutionState = ExecutionState.Stopped;
292          refreshableJob.RefreshAutomatically = false;
293        } else if (
294          lightweightTasks
295            .Where(x => x.ParentTaskId != null)
296            .All(x =>
297              x.State != TaskState.Waiting
298              || x.State != TaskState.Transferring
299              || x.State != TaskState.Calculating)
300          && lightweightTasks
301             .Where(x => x.ParentTaskId != null)
302             .Any(x => x.State == TaskState.Paused)) {
303          refreshableJob.ExecutionState = ExecutionState.Paused;
304          refreshableJob.RefreshAutomatically = false;
305        } else if (lightweightTasks.Any(x => x.State == TaskState.Calculating
306                                  || x.State == TaskState.Transferring
307                                  || x.State == TaskState.Waiting)) {
308          refreshableJob.ExecutionState = ExecutionState.Started;
309        }
310
311        refreshableJob.ExecutionTime = TimeSpan.FromMilliseconds(lightweightTasks.Sum(x => x.ExecutionTime.TotalMilliseconds));
312      }
313    }
314
315    public void SortJobs() {
316      for (int i = 0; i < jobs.Count; i++) {
317        var projectId = jobs.Keys.ElementAt(i);
318        var unsortedJobs = jobs.Values.ElementAt(i);
319
320        var sortedJobs = new HiveItemCollection<RefreshableJob>();
321        sortedJobs.AddRange(unsortedJobs.Where(j => j.Job.State == JobState.DeletionPending));
322        sortedJobs.AddRange(unsortedJobs.Where(j => j.Job.State == JobState.StatisticsPending));
323        sortedJobs.AddRange(unsortedJobs.Where(j => j.Job.State == JobState.Online));
324
325        jobs[projectId] = sortedJobs;
326      }
327    }
328
329    #endregion
330
331    #region Refresh downtime calendar
332    public void RefreshCalendar() {
333      if (downtimeForResourceId != null && downtimeForResourceId != Guid.Empty) {
334        OnRefreshing();
335
336        try {
337          downtimes = new ItemList<Downtime>();
338
339          HiveServiceLocator.Instance.CallHiveService(service => {
340            service.GetDowntimesForResource(downtimeForResourceId).ForEach(d => downtimes.Add(d));
341          });
342        } catch {
343          throw;
344        } finally {
345          OnRefreshed();
346        }
347      }
348    }
349    #endregion
350
351    #region Store
352    public static void Store(IHiveItem item, CancellationToken cancellationToken) {
353      if (item.Id == Guid.Empty) {
354        if (item is SlaveGroup) {
355          item.Id = HiveServiceLocator.Instance.CallHiveService((s) => s.AddSlaveGroup((SlaveGroup)item));
356        }
357        if (item is Slave) {
358          item.Id = HiveServiceLocator.Instance.CallHiveService((s) => s.AddSlave((Slave)item));
359        }
360        if (item is Downtime) {
361          item.Id = HiveServiceLocator.Instance.CallHiveService((s) => s.AddDowntime((Downtime)item));
362        }
363        if (item is Project) {
364          item.Id = HiveServiceLocator.Instance.CallHiveService(s => s.AddProject((Project)item));
365        }
366      } else {
367        if (item is SlaveGroup) {
368          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateSlaveGroup((SlaveGroup)item));
369        }
370        if (item is Slave) {
371          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateSlave((Slave)item));
372        }
373        if (item is Downtime) {
374          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateDowntime((Downtime)item));
375        }
376        if (item is Project) {
377          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateProject((Project)item));
378        }
379      }
380    }
381    #endregion
382
383    #region Delete
384    public static void Delete(IHiveItem item) {
385      if (item is SlaveGroup) {
386        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteSlaveGroup(item.Id));
387      } else if (item is Slave) {
388        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteSlave(item.Id));
389      } else if (item is Downtime) {
390        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteDowntime(item.Id));
391      } else if (item is Project) {
392        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteProject(item.Id));
393      }
394    }
395
396    public static void RemoveJobs(List<Guid> jobIds) {
397      HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateJobStates(jobIds, JobState.StatisticsPending));
398    }
399    #endregion
400
401    #region Job Handling
402
403    public static void ResumeJob(RefreshableJob refreshableJob) {
404      HiveServiceLocator.Instance.CallHiveService(service => {
405        var tasks = service.GetLightweightJobTasksWithoutStateLog(refreshableJob.Id);
406        foreach (var task in tasks) {
407          if (task.State == TaskState.Paused) {
408            service.RestartTask(task.Id);
409          }
410        }
411      });
412      refreshableJob.ExecutionState = ExecutionState.Started;
413    }
414
415    public static void PauseJob(RefreshableJob refreshableJob) {
416      HiveServiceLocator.Instance.CallHiveService(service => {
417        var tasks = service.GetLightweightJobTasksWithoutStateLog(refreshableJob.Id);
418        foreach (var task in tasks) {
419          if (task.State != TaskState.Finished && task.State != TaskState.Aborted && task.State != TaskState.Failed)
420            service.PauseTask(task.Id);
421        }
422      });
423      refreshableJob.ExecutionState = ExecutionState.Paused;
424    }
425
426    public static void StopJob(RefreshableJob refreshableJob) {
427      HiveServiceLocator.Instance.CallHiveService(service => {
428        var tasks = service.GetLightweightJobTasksWithoutStateLog(refreshableJob.Id);
429        foreach (var task in tasks) {
430          if (task.State != TaskState.Finished && task.State != TaskState.Aborted && task.State != TaskState.Failed)
431            service.StopTask(task.Id);
432        }
433      });
434      refreshableJob.ExecutionState = ExecutionState.Stopped;
435    }
436
437    public static void RemoveJob(RefreshableJob refreshableJob) {
438      HiveServiceLocator.Instance.CallHiveService((service) => {
439        service.UpdateJobState(refreshableJob.Id, JobState.StatisticsPending);
440      });
441    }
442    #endregion
443
444    public void ResetDowntime() {
445      downtimeForResourceId = Guid.Empty;
446      if (downtimes != null) {
447        downtimes.Clear();
448      }
449    }
450
451    #region Helper
452    public IEnumerable<Project> GetAvailableProjectAncestors(Guid id) {
453      if (projectAncestors.ContainsKey(id)) return projects.Where(x => projectAncestors[id].Contains(x.Id));
454      else return Enumerable.Empty<Project>();
455    }
456
457    public IEnumerable<Project> GetAvailableProjectDescendants(Guid id) {
458      if (projectDescendants.ContainsKey(id)) return projects.Where(x => projectDescendants[id].Contains(x.Id));
459      else return Enumerable.Empty<Project>();
460    }
461
462    public IEnumerable<Resource> GetAvailableResourceAncestors(Guid id) {
463      if (resourceAncestors.ContainsKey(id)) return resources.Where(x => resourceAncestors[id].Contains(x.Id));
464      else return Enumerable.Empty<Resource>();
465    }
466
467    public IEnumerable<Resource> GetAvailableResourceDescendants(Guid id) {
468      if (resourceDescendants.ContainsKey(id)) return resources.Where(x => resourceDescendants[id].Contains(x.Id));
469      else return Enumerable.Empty<Resource>();
470    }
471
472    public IEnumerable<Resource> GetDisabledResourceAncestors(IEnumerable<Resource> availableResources) {
473      var missingParentIds = availableResources
474        .Where(x => x.ParentResourceId.HasValue)
475        .SelectMany(x => resourceAncestors[x.Id]).Distinct()
476        .Where(x => !availableResources.Select(y => y.Id).Contains(x));
477
478      return resources.OfType<SlaveGroup>().Union(disabledParentResources).Where(x => missingParentIds.Contains(x.Id));
479    }
480
481    public bool CheckAccessToAdminAreaGranted() {
482      if (projects != null) {
483        return projects.Count > 0;
484      } else {
485        bool accessGranted = false;
486        HiveServiceLocator.Instance.CallHiveService(s => {
487          accessGranted = s.CheckAccessToAdminAreaGranted();
488        });
489        return accessGranted;
490      }
491    }
492
493    public bool CheckOwnershipOfResource(Resource res, Guid userId) {
494      if (res == null || userId == Guid.Empty) return false;
495
496      if (res.OwnerUserId == userId) {
497        return true;
498      } else if (resourceAncestors.ContainsKey(res.Id)) {
499        return GetAvailableResourceAncestors(res.Id).Where(x => x.OwnerUserId == userId).Any();
500      }
501
502      return false;
503    }
504
505    public bool CheckOwnershipOfProject(Project pro, Guid userId) {
506      if (pro == null || userId == Guid.Empty) return false;
507
508      if (pro.OwnerUserId == userId) {
509        return true;
510      } else if (projectAncestors.ContainsKey(pro.Id)) {
511        return GetAvailableProjectAncestors(pro.Id).Where(x => x.OwnerUserId == userId).Any();
512      }
513
514      return false;
515    }
516
517    public bool CheckOwnershipOfParentProject(Project pro, Guid userId) {
518      if (pro == null || userId == Guid.Empty) return false;
519
520      if (projectAncestors.ContainsKey(pro.Id)) {
521        return GetAvailableProjectAncestors(pro.Id).Any(x => x.OwnerUserId == userId);
522      }
523
524      if (pro.ParentProjectId != null && pro.ParentProjectId != Guid.Empty) {
525        var parent = projects.FirstOrDefault(x => x.Id == pro.ParentProjectId.Value);
526        if (parent != null)
527          return parent.OwnerUserId == userId || GetAvailableProjectAncestors(parent.Id).Any(x => x.OwnerUserId == userId);
528      }
529
530      return false;
531    }
532
533    public bool CheckParentChange(Project child, Project parent) {
534      bool changePossible = true;
535
536      // change is not possible...
537      // ... if the moved project is null
538      // ... or the new parent is not stored yet
539      // ... or there is not parental change
540      if (child == null
541          || (parent != null && parent.Id == Guid.Empty)
542          || (parent != null && parent.Id == child.ParentProjectId)) {
543        changePossible = false;
544      } else if (parent == null && !IsAdmin()) {
545        // ... if parent is null, but user is no admin (only admins are allowed to create root projects)
546        changePossible = false;
547      } else if (parent != null && (!IsAdmin() && parent.OwnerUserId != UserInformation.Instance.User.Id && !CheckOwnershipOfParentProject(parent, UserInformation.Instance.User.Id))) {
548        // ... if the user is no admin nor owner of the new parent or grand..grandparents
549        changePossible = false;
550      } else if (parent != null && projectDescendants.ContainsKey(child.Id)) {
551        // ... if the new parent is among the moved project's descendants
552        changePossible = !GetAvailableProjectDescendants(child.Id).Where(x => x.Id == parent.Id).Any();
553      }
554
555      return changePossible;
556    }
557
558    public bool CheckParentChange(Resource child, Resource parent) {
559      bool changePossible = true;
560
561      // change is not possisble...
562      // ... if the child resource is null
563      // ... or the child resource equals the parent
564      // ... or the new parent is not stored yet
565      // ... or the new parent is a slave
566      // ... or there is not parental change
567      if (child == null
568        || child == parent
569        || (parent != null && parent.Id == Guid.Empty)
570        || (parent != null && parent is Slave)
571        || (parent != null && parent.Id == child.ParentResourceId)) {
572        changePossible = false;
573      } else if (parent != null && resourceDescendants.ContainsKey(child.Id)) {
574        // ... or if the new parent is among the moved resource's descendants
575        changePossible = !GetAvailableResourceDescendants(child.Id).Where(x => x.Id == parent.Id).Any();
576      }
577
578      return changePossible;
579    }
580
581    public IEnumerable<Resource> GetAssignedResourcesForJob(Guid jobId) {
582      var assignedJobResource = HiveServiceLocator.Instance.CallHiveService(service => service.GetAssignedResourcesForJob(jobId));
583      return Resources.Where(x => assignedJobResource.Select(y => y.ResourceId).Contains(x.Id));
584    }
585
586    private bool IsAdmin() {
587      return HiveRoles.CheckAdminUserPermissions();
588    }
589    #endregion
590  }
591}
Note: See TracBrowser for help on using the repository browser.