Test Failed
Pull Request — master (#2)
by Heiko 'riot'
06:45
created

isomer.ui.instance   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 86
dl 0
loc 170
rs 10
c 0
b 0
f 0
wmc 9

5 Methods

Rating   Name   Duplication   Size   Complexity  
A InstanceInfo.restart_instance() 0 9 1
A InstanceInfo.get_instance_data() 0 24 1
A InstanceInfo.notify_restart_required() 0 8 2
A InstanceInfo.upgrade_isomer() 0 15 1
A InstanceInfo.__init__() 0 28 4
1
#!/usr/bin/env python
2
# -*- coding: UTF-8 -*-
3
4
# Isomer - The distributed application framework
5
# ==============================================
6
# Copyright (C) 2011-2020 Heiko 'riot' Weinen <[email protected]> and others.
7
#
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU Affero General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU Affero General Public License for more details.
17
#
18
# You should have received a copy of the GNU Affero General Public License
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21
"""
22
23
Module: Instance.component
24
=======================
25
26
Instance management component.
27
28
"""
29
30
31
import requests
32
33
from json.decoder import JSONDecodeError
34
from urllib.parse import urljoin
35
36
from isomer.events.system import system_stop
37
from isomer.logger import error, critical, debug
38
from isomer.database import objectmodels
39
from isomer.events.system import authorized_event, isomer_event
40
from isomer.component import ConfigurableComponent, handler
41
from isomer.ui.store import DEFAULT_STORE_URL
42
43
44
class get_instance_data(authorized_event):
45
    """Request general information on the running instance"""
46
    roles = ['admin']
47
48
49
class upgrade_isomer(authorized_event):
50
    """Request an upgrade of Isomer for this instance"""
51
    roles = ['admin']
52
53
54
class restart_instance(authorized_event):
55
    """Request a restart of Isomer for this instance"""
56
    roles = ['admin']
57
58
59
class notify_restart_required(isomer_event):
60
    """Internal notification that a restart will be required """
61
    reason = ""
62
63
64
class InstanceInfo(ConfigurableComponent):
65
    """Instance overview information component for Isomer"""
66
67
    configprops = {
68
        'update_server': {'type': 'string', 'default': DEFAULT_STORE_URL},
69
        'auth': {
70
            'type': 'object',
71
            'properties': {
72
                'username': {'type': 'string'},
73
                'password': {
74
                    'type': 'string',
75
                    'x-schema-form': {'type': 'password'}
76
                }
77
            },
78
            'default': {'username': '', 'password': ''}
79
        }
80
    }
81
82
    def __init__(self, *args, **kwargs):
83
        super(InstanceInfo, self).__init__('INSTANCEINFO', *args, **kwargs)
84
85
        # self.log(self.context.__dict__, pretty=True)
86
87
        systemconfig = objectmodels['systemconfig'].find_one({'active': True})
88
89
        self.needs_restart = False
90
        self.restart_reasons = []
91
92
        url = urljoin(self.config.update_server, "/store/isomer_enrol/")
93
        try:
94
            data = requests.get(
95
                url, auth=(
96
                    self.config.auth['username'], self.config.auth['password'])
97
            )
98
            self.latest_version = data.json()['isomer_enrol']
99
        except (requests.RequestException, JSONDecodeError, KeyError):
100
            self.log("Can't access store isomer version.", lvl=error)
101
            self.log("Store access error:\n", exc=True, lvl=debug)
102
            self.latest_version = "N/A"
103
104
        self.current_version = "N/A"
105
106
        for item in systemconfig.packages:
107
            if item['name'] == "isomer":
108
                self.current_version = ".".join(item['version'].split(".")[:3])
109
                continue
110
111
    @handler(get_instance_data)
112
    def get_instance_data(self, event):
113
        """Handler for general information on the running instance"""
114
115
        obj = self.context.obj
116
117
        result = {
118
            'needs_restart': self.needs_restart,
119
            'restart_reasons': self.restart_reasons,
120
            'latest_version': self.latest_version,
121
            'current_version': self.current_version,
122
            'context': {
123
                'acting_environment': obj['acting_environment'],
124
                'config': obj['config'],
125
                'dbhost': obj['dbhost'],
126
                'dbname': obj['dbname'],
127
                'environment': obj['environment'],
128
                'instance': obj['instance'],
129
                'instance_configuration': obj['instance_configuration']
130
            }
131
        }
132
133
        self._respond(event, result)
134
        return
135
136
    @handler("notify_restart_required")
137
    def notify_restart_required(self, reason):
138
        """Toggles the user interface notification to restart the instance"""
139
140
        self.log("Restart requested by another component for:", reason)
141
        self.needs_restart = True
142
        if reason not in self.restart_reasons:
143
            self.restart_reasons.append(reason)
144
145
    @handler(upgrade_isomer)
146
    def upgrade_isomer(self, event):
147
        """Upgrade Isomer"""
148
149
        self.log("Beginning Isomer upgrade.")
150
151
        upgraded_version = self.latest_version
152
153
        reason = "Upgraded Isomer to " + upgraded_version
154
155
        self.fireEvent(
156
            notify_restart_required(reason)
157
        )
158
159
        self._respond(event, reason)
160
161
    @handler(restart_instance)
162
    def restart_instance(self):
163
        """Terminate the currently running instance and restart it"""
164
165
        self.log("Terminating to restart on admin request", lvl=critical)
166
167
        open("/tmp/isomer_toggle_%s" % self.context.obj['instance'], "a").close()
168
169
        self.fireEvent(system_stop())
170