serverinfo.py 3.87 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json
import os
import socket

ADDRESS_FNAME = 'dbwriter_address'

class ServerInfo:
    def __init__(self, balsam_db_path):
        self.path = os.path.join(balsam_db_path, ADDRESS_FNAME)
        self.data = {}

        if not os.path.exists(self.path):
            self.update(self.data)
        else:
            self.refresh()

17
18
19
        if not self.data.get('balsamdb_path'):
            self.update({'balsamdb_path': balsam_db_path})

20
        if self.data.get('address') and os.environ.get('IS_SERVER_DAEMON')=='True':
21
22
23
24
25
26
            raise RuntimeError(f"A running server address is already posted at {self.path}\n"
                               '  Use "balsam dbserver --stop" to shut it down.\n'
                               '  If you are sure there is no running server process, the'
                               ' daemon did not have a clean shutdown.\n  Use "balsam'
                               ' dbserver --reset <balsam_db_directory>" to reset the server file'
                              )
27
28
29
30
31
32
33
        if self.data.get('host') and os.environ.get('IS_SERVER_DAEMON')=='True':
            raise RuntimeError(f"A running server address is already posted at {self.path}\n"
                               '  Use "balsam dbserver --stop" to shut it down.\n'
                               '  If you are sure there is no running server process, the'
                               ' daemon did not have a clean shutdown.\n  Use "balsam'
                               ' dbserver --reset <balsam_db_directory>" to reset the server file'
                              )
34
35
36
37
38
39
40
41
42
43
44

    def get_free_port_and_address(self):
        hostname = socket.gethostname()
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('', 0))
        port = int(sock.getsockname()[1])
        sock.close()

        address = f'tcp://{hostname}:{port}'
        return address

45
46
47
48
49
50
51
    def get_free_port(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('', 0))
        port = int(sock.getsockname()[1])
        sock.close()
        return port

52
53
54
55
56
    def get_sqlite3_info(self):
        new_address = self.get_free_port_and_address()
        info = dict(db_type='sqlite3', address=new_address)
        return info

57
58
59
    def get_postgres_info(self):
        hostname = socket.gethostname()
        port = self.get_free_port()
60
61
        pg_db_path = os.path.join(self['balsamdb_path'], 'balsamdb')
        info = dict(host=hostname, port=port, pg_db_path=pg_db_path)
62
63
        return info

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    def update_sqlite3_config(self):
        pass

    def update_postgres_config(self):
        conf_path = os.path.join(self['pg_db_path'], 'postgresql.conf')
        config = open(conf_path).read()

        with open(f"{conf_path}.new", 'w') as fp:
            for line in config.split('\n'):
                if line.startswith('port'):
                    port_line = f"port={self['port']} # auto-set by balsam db\n"
                    fp.write(port_line)
                else:
                    fp.write(line + "\n")
        os.rename(f"{conf_path}.new", conf_path)


81
82
83
84
    def reset_server_address(self):
        db = self['db_type']
        info = getattr(self, f'get_{db}_info')()
        self.update(info)
85
        getattr(self, f'update_{db}_config')()
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    
    def update(self, update_dict):
        self.refresh()
        self.data.update(update_dict)
        with open(self.path, 'w') as fp:
            fp.write(json.dumps(self.data))

    def get(self, key, default=None):
        if key in self.data:
            return self.data[key]
        else:
            return default

    def refresh(self):
        if not os.path.exists(self.path): return
        with open(self.path, 'r') as fp:
            self.data = json.loads(fp.read())

    def __getitem__(self, key):
        if self.data is None: self.refresh()
        return self.data[key]

    def __setitem__(self, key, value):
        self.update({key:value})