1 import difflib

2

3 from django.contrib.auth.mixins import LoginRequiredMixin

4 from django.http import HttpResponse

5 from django.shortcuts import get_object_or_404, redirect, render

6 from django.urls import reverse_lazy

7 from django.views.generic import CreateView, DeleteView, DetailView, UpdateView, View

8

9 from meshadmin.server.networks.forms import HostForm

10 from meshadmin.server.networks.mixins import NetworkPermissionMixin

11 from meshadmin.server.networks.models import Host, HostConfig, Network

12 from meshadmin.server.networks.services import generate_config_yaml

13

14

15 class HostDetailView(LoginRequiredMixin, NetworkPermissionMixin, DetailView):

16 model = Host

17 template_name = "networks/host/detail.html"

18

19 def get_network(self):

20 return self.get_object().network

21

22 def get_context_data(self, **kwargs):

23 context = super().get_context_data(**kwargs)

24 fields = [

25 {

26 "name": field.name,

27 "verbose_name": field.verbose_name,

28 "value": getattr(self.object, field.name),

29 }

30 for field in self.model._meta.fields

31 ]

32 config_history = self.object.hostconfig_set.order_by("-created_at")

33 context.update(

34 {

35 "fields": fields,

36 "network": self.object.network,

37 "groups": self.object.groups.all(),

38 "config": config_history.first(),

39 "config_history": config_history,

40 }

41 )

42 return context

43

44

45 class HostCreateView(LoginRequiredMixin, NetworkPermissionMixin, CreateView):

46 model = Host

47 form_class = HostForm

48 template_name = "networks/shared/form.html"

49

50 def get_network(self):

51 return get_object_or_404(Network, id=self.kwargs.get("network_id"))

52

53 def get_success_url(self):

54 return reverse_lazy("networks:host-detail", kwargs={"pk": self.object.pk})

55

56 def get_form_kwargs(self):

57 kwargs = super().get_form_kwargs()

58 network_id = self.kwargs.get("network_id")

59 if network_id:

60 network = get_object_or_404(Network, id=network_id)

61 kwargs["network"] = network

62 return kwargs

63

64 def get_context_data(self, **kwargs):

65 context = super().get_context_data(**kwargs)

66 context.update(

67 {

68 "action": "Create",

69 "model_name": self.model._meta.verbose_name,

70 "network_id": self.kwargs.get("network_id"),

71 }

72 )

73 return context

74

75

76 class HostUpdateView(LoginRequiredMixin, NetworkPermissionMixin, UpdateView):

77 model = Host

78 form_class = HostForm

79 template_name = "networks/shared/form.html"

80

81 def get_network(self):

82 return self.get_object().network

83

84 def get_success_url(self):

85 return reverse_lazy("networks:host-detail", kwargs={"pk": self.object.pk})

86

87 def get_context_data(self, **kwargs):

88 context = super().get_context_data(**kwargs)

89 context["action"] = "Update"

90 return context

91

92

93 class HostDeleteView(LoginRequiredMixin, NetworkPermissionMixin, DeleteView):

94 model = Host

95 template_name = "networks/shared/delete.html"

96

97 def get_network(self):

98 return self.get_object().network

99

100 def get_success_url(self):

101 return (

102 reverse_lazy(

103 "networks:network-detail", kwargs={"pk": self.object.network.pk}

104 )

105 + "#hosts-section"

106 )

107

108 def get_context_data(self, **kwargs):

109 context = super().get_context_data(**kwargs)

110 context["model_name"] = self.model._meta.verbose_name

111 return context

112

113

114 class HostConfigView(LoginRequiredMixin, View):

115 def get(self, request, pk):

116 get_object_or_404(Host, id=pk)

117 config = generate_config_yaml(pk)

118 return HttpResponse(config, content_type="text/yaml")

119

120

121 class ConfigDiffView(LoginRequiredMixin, View):

122 def get(self, request, base_id, compare_id):

123 try:

124 base_config = get_object_or_404(HostConfig, id=base_id)

125 compare_config = get_object_or_404(HostConfig, id=compare_id)

126 diff = list(

127 difflib.unified_diff(

128 base_config.config.splitlines(),

129 compare_config.config.splitlines(),

130 fromfile=f"Version {base_config.created_at:%Y-%m-%d %H:%M}",

131 tofile=f"Version {compare_config.created_at:%Y-%m-%d %H:%M}",

132 lineterm="",

133 )

134 )

135 context = {

136 "diff": diff,

137 "has_changes": bool(diff),

138 "base_time": base_config.created_at.strftime("%Y-%m-%d %H:%M"),

139 "compare_time": compare_config.created_at.strftime("%Y-%m-%d %H:%M"),

140 }

141 return render(request, "networks/host/diff.html", context)

142 except Exception:

143 context = {"error": "Error generating diff"}

144 return render(request, "networks/host/diff.html", context)

145

146

147 class HostRefreshConfigView(LoginRequiredMixin, View):

148 def post(self, request, pk, rollout_id):

149 host = get_object_or_404(Host, id=pk)

150 generate_config_yaml(host.id, ignore_freeze=True)

151 return redirect("networks:rollout-detail", pk=rollout_id)

152

153

154 class HostUpgradeView(LoginRequiredMixin, View):

155 def post(self, request, pk):

156 host = get_object_or_404(Host, id=pk)

157 host.upgrade_requested = True

158 host.save()

159 return render(request, "networks/host/upgrade_button.html", {"object": host})