Initial YakPanel commit
This commit is contained in:
1
class/projectModel/__init__.py
Normal file
1
class/projectModel/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
63
class/projectModel/base.py
Normal file
63
class/projectModel/base.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#coding: utf-8
|
||||
import public,re
|
||||
|
||||
class projectBase:
|
||||
|
||||
def check_port(self, port):
|
||||
'''
|
||||
@name 检查端口是否被占用
|
||||
@args port:端口号
|
||||
@return: 被占用返回True,否则返回False
|
||||
@author: lkq 2021-08-28
|
||||
'''
|
||||
a = public.ExecShell("netstat -nltp|awk '{print $4}'")
|
||||
if a[0]:
|
||||
if re.search(':' + port + '\n', a[0]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_domain(self, domain):
|
||||
'''
|
||||
@name 验证域名合法性
|
||||
@args domain:域名
|
||||
@return: 合法返回True,否则返回False
|
||||
@author: lkq 2021-08-28
|
||||
'''
|
||||
import re
|
||||
domain_regex = re.compile(r'(?:[A-Z0-9_](?:[A-Z0-9-_]{0,247}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))\Z', re.IGNORECASE)
|
||||
return True if domain_regex.match(domain) else False
|
||||
|
||||
|
||||
def generate_random_port(self):
|
||||
'''
|
||||
@name 生成随机端口
|
||||
@args
|
||||
@return: 端口号
|
||||
@author: lkq 2021-08-28
|
||||
'''
|
||||
import random
|
||||
port = str(random.randint(5000, 10000))
|
||||
while True:
|
||||
if not self.check_port(port): break
|
||||
port = str(random.randint(5000, 10000))
|
||||
return port
|
||||
|
||||
def IsOpen(self, port):
|
||||
'''
|
||||
@name 检查端口是否被占用
|
||||
@args port:端口号
|
||||
@return: 被占用返回True,否则返回False
|
||||
@author: lkq 2021-08-28
|
||||
'''
|
||||
ip = '0.0.0.0'
|
||||
import socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(2)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
0
class/projectModel/bt_docker/__init__.py
Normal file
0
class/projectModel/bt_docker/__init__.py
Normal file
Binary file not shown.
337
class/projectModel/bt_docker/dk_compose.py
Normal file
337
class/projectModel/bt_docker/dk_compose.py
Normal file
@@ -0,0 +1,337 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import public #line:13
|
||||
import os #line:14
|
||||
import time #line:15
|
||||
import projectModel .bt_docker .dk_public as dp #line:16
|
||||
import projectModel .bt_docker .dk_container as dc #line:17
|
||||
import projectModel .bt_docker .dk_setup as ds #line:18
|
||||
import json #line:19
|
||||
class main :#line:22
|
||||
compose_path ="{}/data/compose".format (public .get_panel_path ())#line:23
|
||||
__O00OO0OO00O0OO000 ="/tmp/dockertmp.log"#line:24
|
||||
def check_conf (O0OO0OO00OO0OOO00 ,O0OOOOOOO00O00O00 ):#line:27
|
||||
OOO0OOO0OOO0000O0 ="/usr/bin/docker-compose -f {} config".format (O0OOOOOOO00O00O00 )#line:28
|
||||
O0O0000OOOO0O0O0O ,OOOO00O0O00OOO0O0 =public .ExecShell (OOO0OOO0OOO0000O0 )#line:29
|
||||
if OOOO00O0O00OOO0O0 :#line:30
|
||||
return public .return_msg_gettext (False ,"Check failed:{}".format (OOOO00O0O00OOO0O0 ))#line:31
|
||||
return public .return_msg_gettext (True ,"Passed!")#line:32
|
||||
def add_template_gui (O0O0OOOOOOO00O000 ,O0000O0O0O0O00O00 ):#line:35
|
||||
""#line:69
|
||||
import yaml #line:70
|
||||
O000000OOO0O00OO0 ="{}/template".format (O0O0OOOOOOO00O000 .compose_path )#line:71
|
||||
O0O00000OO000OO0O ="{}/{}.yaml".format (O000000OOO0O00OO0 ,O0000O0O0O0O00O00 .name )#line:72
|
||||
if not os .path .exists (O000000OOO0O00OO0 ):#line:73
|
||||
os .makedirs (O000000OOO0O00OO0 )#line:74
|
||||
O000O0O000O0OOOO0 =json .loads (O0000O0O0O0O00O00 .data )#line:75
|
||||
yaml .dump (O000O0O000O0OOOO0 ,O0O00000OO000OO0O )#line:76
|
||||
def get_template_kw (O0OOO0OO0OOO0000O ,OO00OO000OOOOOOOO ):#line:78
|
||||
O0OO0OO0O00O0OO0O ={"version":"","services":{"server_name_str":{"build":{"context":"str","dockerfile":"str","args":[],"cache_from":[],"labels":[],"network":"str","shm_size":"str","target":"str"},"cap_add":"","cap_drop":"","cgroup_parent":"str","command":"str","configs":{"my_config_str":[]},"container_name":"str","credential_spec":{"file":"str","registry":"str"},"depends_on":[],"deploy":{"endpoint_mode":"str","labels":{"key":"value"},"mode":"str","placement":[{"key":"value"}],"max_replicas_per_node":"int","replicas":"int","resources":{"limits":{"cpus":"str","memory":"str",},"reservations":{"cpus":"str","memory":"str",},"restart_policy":{"condition":"str","delay":"str","max_attempts":"int","window":"str"}}}}}}#line:134
|
||||
def add_template (OO0O00000000O00OO ,O00OOOOOO0O0O0000 ):#line:137
|
||||
""#line:145
|
||||
OO00O0OO0O0O0000O =OO0O00000000O00OO .template_list (O00OOOOOO0O0O0000 )['msg']['template']#line:146
|
||||
for O0O00O000OO000OO0 in OO00O0OO0O0O0000O :#line:147
|
||||
if O00OOOOOO0O0O0000 .name ==O0O00O000OO000OO0 ['name']:#line:148
|
||||
return public .return_msg_gettext (False ,"This template name already exists!")#line:149
|
||||
OO0OOOOO0OO0O0OOO ="{}/{}/template".format (OO0O00000000O00OO .compose_path ,O00OOOOOO0O0O0000 .name )#line:150
|
||||
O00OOO00O0O0O0OOO ="{}/{}.yaml".format (OO0OOOOO0OO0O0OOO ,O00OOOOOO0O0O0000 .name )#line:151
|
||||
if not os .path .exists (OO0OOOOO0OO0O0OOO ):#line:152
|
||||
os .makedirs (OO0OOOOO0OO0O0OOO )#line:153
|
||||
public .writeFile (O00OOO00O0O0O0OOO ,O00OOOOOO0O0O0000 .data )#line:154
|
||||
OOO0000O000O0OO00 =OO0O00000000O00OO .check_conf (O00OOO00O0O0O0OOO )#line:155
|
||||
if not OOO0000O000O0OO00 ['status']:#line:156
|
||||
if os .path .exists (O00OOO00O0O0O0OOO ):#line:157
|
||||
os .remove (O00OOO00O0O0O0OOO )#line:158
|
||||
return OOO0000O000O0OO00 #line:160
|
||||
O0O0OO0O00OO00OO0 ={"name":O00OOOOOO0O0O0000 .name ,"remark":O00OOOOOO0O0O0000 .remark ,"path":O00OOO00O0O0O0OOO }#line:165
|
||||
dp .sql ("templates").insert (O0O0OO0O00OO00OO0 )#line:166
|
||||
dp .write_log ("Add template [{}] successful!".format (O00OOOOOO0O0O0000 .name ))#line:167
|
||||
return public .return_msg_gettext (True ,"Template added successfully!")#line:169
|
||||
def edit_template (OOOO00O0OOOOO0O00 ,O00O0O0O000O0O000 ):#line:171
|
||||
""#line:178
|
||||
O0O00OOO00OOOO00O =dp .sql ("templates").where ("id=?",(O00O0O0O000O0O000 .id ,)).find ()#line:179
|
||||
if not O0O00OOO00OOOO00O :#line:180
|
||||
return public .return_msg_gettext (False ,"This template was not found!")#line:181
|
||||
public .writeFile (O0O00OOO00OOOO00O ['path'],O00O0O0O000O0O000 .data )#line:182
|
||||
O0OOOO0O0000OOO0O =OOOO00O0OOOOO0O00 .check_conf (O0O00OOO00OOOO00O ['path'])#line:183
|
||||
if not O0OOOO0O0000OOO0O ['status']:#line:184
|
||||
return O0OOOO0O0000OOO0O #line:185
|
||||
OOOOO0OO00OOO000O ={"name":O0O00OOO00OOOO00O ['name'],"remark":O00O0O0O000O0O000 .remark ,"path":O0O00OOO00OOOO00O ['path']}#line:190
|
||||
dp .sql ("templates").where ("id=?",(O00O0O0O000O0O000 .id ,)).update (OOOOO0OO00OOO000O )#line:191
|
||||
dp .write_log ("Editing template [{}] succeeded!".format (O0O00OOO00OOOO00O ['name']))#line:192
|
||||
return public .return_msg_gettext (True ,"Modify the template successfully!")#line:193
|
||||
def get_template (O0O000OO00O0OO0O0 ,O0OOOO00O00O00OO0 ):#line:195
|
||||
""#line:200
|
||||
OOO0OO0OO0OO0000O =dp .sql ("templates").where ("id=?",(O0OOOO00O00O00OO0 .id ,)).find ()#line:201
|
||||
if not OOO0OO0OO0OO0000O :#line:202
|
||||
return public .return_msg_gettext (False ,"This template was not found!")#line:203
|
||||
return public .return_msg_gettext (True ,public .readFile (OOO0OO0OO0OO0000O ['path']))#line:204
|
||||
def template_list (OOO00OO000O0OOO0O ,O00O0O00OOO00O000 ):#line:206
|
||||
""#line:211
|
||||
import projectModel .bt_docker .dk_setup as ds #line:212
|
||||
OOOO0OO00OOOO0O0O =ds .main ()#line:213
|
||||
OOO0OO00OO0OO0O0O =dp .sql ("templates").select ()[::-1 ]#line:214
|
||||
if not isinstance (OOO0OO00OO0OO0O0O ,list ):#line:215
|
||||
OOO0OO00OO0OO0O0O =[]#line:216
|
||||
OOOO0O000OO0OO0O0 ={"template":OOO0OO00OO0OO0O0O ,"installed":OOOO0OO00OOOO0O0O .check_docker_program (),"service_status":OOOO0OO00OOOO0O0O .get_service_status ()}#line:221
|
||||
return public .return_msg_gettext (True ,OOOO0O000OO0OO0O0 )#line:222
|
||||
def remove_template (O0O0O0OOOOO0O000O ,OO0OO0OO00O000OOO ):#line:224
|
||||
""#line:230
|
||||
O00OO00O0OOO0000O =dp .sql ("templates").where ("id=?",(OO0OO0OO00O000OOO .template_id ,)).find ()#line:231
|
||||
if not O00OO00O0OOO0000O :#line:232
|
||||
return public .return_msg_gettext (False ,"This template was not found!")#line:233
|
||||
if os .path .exists (O00OO00O0OOO0000O ['path']):#line:234
|
||||
os .remove (O00OO00O0OOO0000O ['path'])#line:235
|
||||
dp .sql ("templates").delete (id =OO0OO0OO00O000OOO .template_id )#line:236
|
||||
dp .write_log ("Delete template [{}] successful!".format (O00OO00O0OOO0000O ['name']))#line:237
|
||||
return public .return_msg_gettext (True ,"Successfully deleted!")#line:238
|
||||
def edit_project_remark (OOO0O0000OO000000 ,OO00000OO000OOOO0 ):#line:240
|
||||
""#line:247
|
||||
O0OOOOOO000OOO0OO =dp .sql ("stacks").where ("id=?",(OO00000OO000OOOO0 .project_id ,)).find ()#line:248
|
||||
if not O0OOOOOO000OOO0OO :#line:249
|
||||
return public .return_msg_gettext (False ,"The item was not found!")#line:250
|
||||
OO0OOO00OO0OOO000 ={"remark":OO00000OO000OOOO0 .remark }#line:253
|
||||
dp .write_log ("Modify the item[{}] remarks [{}] to [{}] success!".format (O0OOOOOO000OOO0OO ['name'],O0OOOOOO000OOO0OO ['remark'],OO00000OO000OOOO0 .remark ))#line:254
|
||||
dp .sql ("stacks").where ("id=?",(OO00000OO000OOOO0 .project_id ,)).update (OO0OOO00OO0OOO000 )#line:255
|
||||
def edit_template_remark (O000000OOOOO0O000 ,OOOO0OOOO0O0O0OO0 ):#line:257
|
||||
""#line:264
|
||||
OO0OO00OOOOO0OO00 =dp .sql ("templates").where ("id=?",(OOOO0OOOO0O0O0OO0 .templates_id ,)).find ()#line:265
|
||||
if not OO0OO00OOOOO0OO00 :#line:266
|
||||
return public .return_msg_gettext (False ,"The template was not found!")#line:267
|
||||
OO0O0O0OO0OOOOOOO ={"remark":OOOO0OOOO0O0O0OO0 .remark }#line:270
|
||||
dp .write_log ("Modify the template [{}] remarks [{}] to [{}] successful!".format (OO0OO00OOOOO0OO00 ['name'],OO0OO00OOOOO0OO00 ['remark'],OOOO0OOOO0O0O0OO0 .remark ))#line:271
|
||||
dp .sql ("templates").where ("id=?",(OOOO0OOOO0O0O0OO0 .templates_id ,)).update (OO0O0O0OO0OOOOOOO )#line:272
|
||||
def create_project_in_path (OO00000O0000O0O00 ,O0OO0OOOO0000OO00 ,O000O0O0O0OO00000 ):#line:274
|
||||
OO000OO000O0O00O0 ="cd {} && /usr/bin/docker-compose -p {} up -d &> {}".format ("/".join (O000O0O0O0OO00000 .split ("/")[:-1 ]),O0OO0OOOO0000OO00 ,OO00000O0000O0O00 .__O00OO0OO00O0OO000 )#line:275
|
||||
public .ExecShell (OO000OO000O0O00O0 )#line:276
|
||||
def create_project_in_file (O00OO0O0OO0OO00OO ,O0O0O0O00O000000O ,O00000O0OOOO0OOOO ):#line:278
|
||||
O0000OO0O0O000OO0 ="{}/{}".format (O00OO0O0OO0OO00OO .compose_path ,O0O0O0O00O000000O )#line:279
|
||||
O000OO00OOOOO00OO ="{}/docker-compose.yaml".format (O0000OO0O0O000OO0 )#line:280
|
||||
if not os .path .exists (O0000OO0O0O000OO0 ):#line:281
|
||||
os .makedirs (O0000OO0O0O000OO0 )#line:282
|
||||
O00OOO000O000O000 =public .readFile (O00000O0OOOO0OOOO )#line:283
|
||||
public .writeFile (O000OO00OOOOO00OO ,O00OOO000O000O000 )#line:284
|
||||
O000O0OOOO0OO0O0O ="/usr/bin/docker-compose -p {} -f {} up -d &> {}".format (O0O0O0O00O000000O ,O000OO00OOOOO00OO ,O00OO0O0OO0OO00OO .__O00OO0OO00O0OO000 )#line:285
|
||||
public .ExecShell (O000O0OOOO0OO0O0O )#line:286
|
||||
def check_project_container_name (OOOO00OO0OOOOO0OO ,OO0OOOO0O00OO0OO0 ,OOO0OO00OO0OO00OO ):#line:288
|
||||
""#line:292
|
||||
import re #line:293
|
||||
import projectModel .bt_docker .dk_container as dc #line:294
|
||||
OO00OOOOO0O0OOOOO =[]#line:295
|
||||
O0OOOO000O00OOO0O =re .findall ("container_name\\s*:\\s*[\"\']+(.*)[\'\"]",OO0OOOO0O00OO0OO0 )#line:296
|
||||
O0O0OO0O00OOO0O00 =dc .main ().get_list (OOO0OO00OO0OO00OO )#line:297
|
||||
if not O0O0OO0O00OOO0O00 ["status"]:#line:298
|
||||
return public .return_msg_gettext (False ,"Error getting container list!")#line:299
|
||||
O0O0OO0O00OOO0O00 =O0O0OO0O00OOO0O00 ['msg']['container_list']#line:300
|
||||
for O0OOO0O0OO0O0OO00 in O0O0OO0O00OOO0O00 :#line:301
|
||||
if O0OOO0O0OO0O0OO00 ['name']in O0OOOO000O00OOO0O :#line:302
|
||||
OO00OOOOO0O0OOOOO .append (O0OOO0O0OO0O0OO00 ['name'])#line:303
|
||||
if OO00OOOOO0O0OOOOO :#line:304
|
||||
return public .return_msg_gettext (False ,"The container name in the template: <br>[{}] already exists!".format (", ".join (OO00OOOOO0O0OOOOO )))#line:305
|
||||
OO0000O0OO00OO0O0 =r"(\d+):\d+"#line:307
|
||||
O00O00OOOO0OO00O0 =re .findall (OO0000O0OO00OO0O0 ,OO0OOOO0O00OO0OO0 )#line:308
|
||||
for O0OOO00O00O0OOOOO in O00O00OOOO0OO00O0 :#line:309
|
||||
if dp .check_socket (O0OOO00O00O0OOOOO ):#line:310
|
||||
return public .return_msg_gettext (False ,"The port [{}] in the template is already in use, please modify the server port in the template!".format (O0OOO00O00O0OOOOO ))#line:311
|
||||
def create (OO0O00O0OO00O0OO0 ,O0O0O0O00OO0OOOO0 ):#line:314
|
||||
""#line:321
|
||||
OOO00OO0O00OOOO0O =public .md5 (O0O0O0O00OO0OOOO0 .project_name )#line:322
|
||||
OO000O00O00O0000O =dp .sql ("templates").where ("id=?",(O0O0O0O00OO0OOOO0 .template_id ,)).find ()#line:323
|
||||
if not os .path .exists (OO000O00O00O0000O ['path']):#line:324
|
||||
return public .return_msg_gettext (False ,"Template file not found")#line:325
|
||||
O00O0OOOOO0OO0OOO =OO0O00O0OO00O0OO0 .check_project_container_name (public .readFile (OO000O00O00O0000O ['path']),O0O0O0O00OO0OOOO0 )#line:326
|
||||
if O00O0OOOOO0OO0OOO :#line:327
|
||||
return O00O0OOOOO0OO0OOO #line:328
|
||||
O000000O0000OOOOO =dp .sql ("stacks").where ("name=?",(OOO00OO0O00OOOO0O )).find ()#line:329
|
||||
if not O000000O0000OOOOO :#line:330
|
||||
O0OOO0OOO0O0OO0OO ={"name":O0O0O0O00OO0OOOO0 .project_name ,"status":"1","path":OO000O00O00O0000O ['path'],"template_id":O0O0O0O00OO0OOOO0 .template_id ,"time":time .time (),"remark":O0O0O0O00OO0OOOO0 .remark }#line:338
|
||||
dp .sql ("stacks").insert (O0OOO0OOO0O0OO0OO )#line:339
|
||||
else :#line:340
|
||||
return public .return_msg_gettext (False ,"This project name already exists!")#line:341
|
||||
if OO000O00O00O0000O ['add_in_path']==1 :#line:342
|
||||
OO0O00O0OO00O0OO0 .create_project_in_path (OOO00OO0O00OOOO0O ,OO000O00O00O0000O ['path'])#line:346
|
||||
else :#line:347
|
||||
OO0O00O0OO00O0OO0 .create_project_in_file (OOO00OO0O00OOOO0O ,OO000O00O00O0000O ['path'])#line:351
|
||||
dp .write_log ("Project [{}] is successfully deployed!".format (OOO00OO0O00OOOO0O ))#line:352
|
||||
return public .return_msg_gettext (True ,"Deployment succeeded!")#line:354
|
||||
def compose_project_list (OOOOOO0OO00O0OO0O ,OO0O0000O00O0O000 ):#line:370
|
||||
""#line:373
|
||||
OO0O0000O00O0O000 .url ="unix:///var/run/docker.sock"#line:374
|
||||
O0O000O0000OOO000 =dc .main ().get_list (OO0O0000O00O0O000 )#line:375
|
||||
if not O0O000O0000OOO000 ['status']:#line:376
|
||||
return public .return_msg_gettext (False ,"Failed to get the container, maybe the docker service is not started!")#line:377
|
||||
if not O0O000O0000OOO000 ['msg']['service_status']or not O0O000O0000OOO000 ['msg']['installed']:#line:378
|
||||
OO0OOO0OO00000OO0 ={"project_list":[],"template":[],"service_status":O0O000O0000OOO000 ['msg']['service_status'],"installed":O0O000O0000OOO000 ['msg']['installed']}#line:384
|
||||
return public .return_msg_gettext (True ,OO0OOO0OO00000OO0 )#line:385
|
||||
OO000O00000O00O0O =dp .sql ("stacks").select ()#line:386
|
||||
if isinstance (OO000O00000O00O0O ,list ):#line:387
|
||||
for O0OOOO0O000O00O00 in OO000O00000O00O0O :#line:388
|
||||
OOOOOO0OO00OOOO0O =[]#line:389
|
||||
for O0000OOO000000OOO in O0O000O0000OOO000 ['msg']["container_list"]:#line:390
|
||||
try :#line:391
|
||||
if 'com.docker.compose.project'not in O0000OOO000000OOO ["detail"]['Config']['Labels']:#line:392
|
||||
continue #line:393
|
||||
except :#line:394
|
||||
continue #line:395
|
||||
if O0000OOO000000OOO ["detail"]['Config']['Labels']['com.docker.compose.project']==public .md5 (O0OOOO0O000O00O00 ['name']):#line:396
|
||||
OOOOOO0OO00OOOO0O .append (O0000OOO000000OOO )#line:397
|
||||
O00OOOOO0O0OO0000 =OOOOOO0OO00OOOO0O #line:398
|
||||
O0OOOO0O000O00O00 ['container']=O00OOOOO0O0OO0000 #line:399
|
||||
else :#line:400
|
||||
OO000O00000O00O0O =[]#line:401
|
||||
OO0OOO0OO0OO00OOO =OOOOOO0OO00O0OO0O .template_list (OO0O0000O00O0O000 )#line:402
|
||||
if not OO0OOO0OO0OO00OOO ['status']:#line:403
|
||||
OO0OOO0OO0OO00OOO =list ()#line:404
|
||||
else :#line:405
|
||||
OO0OOO0OO0OO00OOO =OO0OOO0OO0OO00OOO ['msg']['template']#line:406
|
||||
OO0O0O00OOO000O0O =ds .main ()#line:407
|
||||
OO0OOO0OO00000OO0 ={"project_list":OO000O00000O00O0O ,"template":OO0OOO0OO0OO00OOO ,"service_status":OO0O0O00OOO000O0O .get_service_status (),"installed":OO0O0O00OOO000O0O .check_docker_program ()}#line:413
|
||||
return public .return_msg_gettext (True ,OO0OOO0OO00000OO0 )#line:414
|
||||
def remove (O0O0O0O0OO00OOOOO ,OOO0O00OOO0OOOO00 ):#line:417
|
||||
""#line:422
|
||||
O0OO0OOO00O000OOO =dp .sql ("stacks").where ("id=?",(OOO0O00OOO0OOOO00 .project_id ,)).find ()#line:423
|
||||
if not O0OO0OOO00O000OOO :#line:424
|
||||
return public .return_msg_gettext (True ,"The project configuration was not found!")#line:425
|
||||
OO0000000000O000O ="/usr/bin/docker-compose -p {} -f {} down &> {}".format (public .md5 (O0OO0OOO00O000OOO ['name']),O0OO0OOO00O000OOO ['path'],O0O0O0O0OO00OOOOO .__O00OO0OO00O0OO000 )#line:426
|
||||
OO0O0OOO00O00OO00 ,O00OO00O0000000O0 =public .ExecShell (OO0000000000O000O )#line:427
|
||||
dp .sql ("stacks").delete (id =OOO0O00OOO0OOOO00 .project_id )#line:428
|
||||
dp .write_log ("Delete item [{}] succeeded!".format (O0OO0OOO00O000OOO ['name']))#line:429
|
||||
return public .return_msg_gettext (True ,"Successfully deleted!")#line:430
|
||||
def stop (O0OOO0OOOOOO00O00 ,OOOO0OOO0OO00OO00 ):#line:433
|
||||
""#line:439
|
||||
O00O000O00OOO00O0 =dp .sql ("stacks").where ("id=?",(OOOO0OOO0OO00OO00 .project_id ,)).find ()#line:440
|
||||
if not O00O000O00OOO00O0 :#line:441
|
||||
return public .return_msg_gettext (True ,"The project configuration was not found!")#line:442
|
||||
OO0OO0OOO0O0O00O0 ="/usr/bin/docker-compose -p {} -f {} stop &> {}".format (public .md5 (O00O000O00OOO00O0 ['name']),O00O000O00OOO00O0 ['path'],O0OOO0OOOOOO00O00 .__O00OO0OO00O0OO000 )#line:444
|
||||
OO0O00O0000OOOOOO ,O0OO00000O0OO00O0 =public .ExecShell (OO0OO0OOO0O0O00O0 )#line:445
|
||||
dp .write_log ("Stop project [{}] succeeded!".format (O00O000O00OOO00O0 ['name']))#line:446
|
||||
return public .return_msg_gettext (True ,"Set up successfully!")#line:447
|
||||
def start (O000OO00OOO0000O0 ,O0000O000OO0OOOO0 ):#line:450
|
||||
""#line:455
|
||||
OO00O000000OO00O0 =dp .sql ("stacks").where ("id=?",(O0000O000OO0OOOO0 .project_id ,)).find ()#line:456
|
||||
if not OO00O000000OO00O0 :#line:457
|
||||
return public .return_msg_gettext (False ,"The project configuration was not found!")#line:458
|
||||
O0OO000O0OOO0OO0O ="/usr/bin/docker-compose -p {} -f {} start > {}".format (public .md5 (OO00O000000OO00O0 ['name']),OO00O000000OO00O0 ['path'],O000OO00OOO0000O0 .__O00OO0OO00O0OO000 )#line:459
|
||||
O00O000OOO00O000O ,O0O00OO0OO0OO0OOO =public .ExecShell (O0OO000O0OOO0OO0O )#line:460
|
||||
dp .write_log ("Startup project [{}] succeeded!".format (OO00O000000OO00O0 ['name']))#line:461
|
||||
return public .return_msg_gettext (True ,"Set up successfully!")#line:462
|
||||
def restart (O0OO00OO0O0OOO00O ,O000OOOOOOO00O0OO ):#line:465
|
||||
""#line:470
|
||||
OO000OOOOO0OO0O0O =dp .sql ("stacks").where ("id=?",(O000OOOOOOO00O0OO .project_id ,)).find ()#line:471
|
||||
if not OO000OOOOO0OO0O0O :#line:472
|
||||
return public .return_msg_gettext (True ,"The project configuration was not found!")#line:473
|
||||
O00O00O000OO00O0O ="/usr/bin/docker-compose -p {} -f {} restart &> {}".format (public .md5 (OO000OOOOO0OO0O0O ['name']),OO000OOOOO0OO0O0O ['path'],O0OO00OO0O0OOO00O .__O00OO0OO00O0OO000 )#line:474
|
||||
O00OO0000O0000OO0 ,O0OOOOO000OO0O0O0 =public .ExecShell (O00O00O000OO00O0O )#line:475
|
||||
dp .write_log ("Restart the project [{}] successfully!".format (OO000OOOOO0OO0O0O ['name']))#line:476
|
||||
return public .return_msg_gettext (True ,"Set up successfully!")#line:477
|
||||
def pull (OOO0OO00O0OO00OO0 ,OO0OOOOOO00000OO0 ):#line:480
|
||||
""#line:485
|
||||
O0OO0OO0OO0O0OOO0 =dp .sql ("templates").where ("id=?",(OO0OOOOOO00000OO0 .template_id ,)).find ()#line:486
|
||||
if not O0OO0OO0OO0O0OOO0 :#line:487
|
||||
return public .return_msg_gettext (True ,"The template was not found!")#line:488
|
||||
O0OOOO0O000O0O000 ="/usr/bin/docker-compose -p {} -f {} pull &> {}".format (O0OO0OO0OO0O0OOO0 ['name'],O0OO0OO0OO0O0OOO0 ['path'],OOO0OO00O0OO00OO0 .__O00OO0OO00O0OO000 )#line:489
|
||||
O0O00OOO0O0O0OO00 ,OO000OOO0O000OOO0 =public .ExecShell (O0OOOO0O000O0O000 )#line:490
|
||||
dp .write_log ("The mirror image of the template [{}] was pulled successfully!".format (O0OO0OO0OO0O0OOO0 ['name']))#line:491
|
||||
return public .return_msg_gettext (True ,"Pull success!")#line:492
|
||||
def pause (OOO00O0OO00O00O0O ,O0OOOOO000OO0000O ):#line:495
|
||||
""#line:500
|
||||
OO0O0000OOO000O00 =dp .sql ("stacks").where ("id=?",(O0OOOOO000OO0000O .project_id ,)).find ()#line:501
|
||||
if not OO0O0000OOO000O00 :#line:502
|
||||
return public .return_msg_gettext (True ,"The project configuration was not found!")#line:503
|
||||
O0O0OOO0000O0O00O ="/usr/bin/docker-compose -p {} -f {} pause &> {}".format (public .md5 (OO0O0000OOO000O00 ['name']),OO0O0000OOO000O00 ['path'],OOO00O0OO00O00O0O .__O00OO0OO00O0OO000 )#line:504
|
||||
O0000OO0OOO00OOOO ,O0O0O0OOO0O0O0OOO =public .ExecShell (O0O0OOO0000O0O00O )#line:505
|
||||
dp .write_log ("Pause [{}] success!".format (OO0O0000OOO000O00 ['name']))#line:506
|
||||
return public .return_msg_gettext (True ,"Set up successfully!")#line:507
|
||||
def unpause (O0O0O0OOO00OOOO00 ,O0O00O000OOO00OO0 ):#line:510
|
||||
""#line:515
|
||||
OO0O0OO00OOO00O00 =dp .sql ("stacks").where ("id=?",(O0O00O000OOO00OO0 .project_id ,)).find ()#line:516
|
||||
if not OO0O0OO00OOO00O00 :#line:517
|
||||
return public .return_msg_gettext (True ,"The project configuration was not found!")#line:518
|
||||
OOO00O00OOOO0OO00 ="/usr/bin/docker-compose -p {} -f {} unpause &> {}".format (public .md5 (OO0O0OO00OOO00O00 ['name']),OO0O0OO00OOO00O00 ['path'],O0O0O0OOO00OOOO00 .__O00OO0OO00O0OO000 )#line:519
|
||||
O00000OOO000OOO0O ,O00OO00O0O0O00OO0 =public .ExecShell (OOO00O00OOOO0OO00 )#line:520
|
||||
dp .write_log ("Unsuspended project [{}] succeeded!".format (OO0O0OO00OOO00O00 ['name']))#line:521
|
||||
return public .return_msg_gettext (True ,"Set up successfully!")#line:522
|
||||
def scan_compose_file (OOO000OO000OOOOOO ,O00000OOO00O00OOO ,O000O00O0OOO0O0OO ):#line:525
|
||||
""#line:531
|
||||
O0OOOO0O00OOO00O0 =os .listdir (O00000OOO00O00OOO )#line:532
|
||||
for OO00000OOO00OOOO0 in O0OOOO0O00OOO00O0 :#line:533
|
||||
OO0O0OO00OO0OO000 =os .path .join (O00000OOO00O00OOO ,OO00000OOO00OOOO0 )#line:534
|
||||
if os .path .isdir (OO0O0OO00OO0OO000 ):#line:536
|
||||
OOO000OO000OOOOOO .scan_compose_file (OO0O0OO00OO0OO000 ,O000O00O0OOO0O0OO )#line:537
|
||||
else :#line:538
|
||||
if OO00000OOO00OOOO0 =="docker-compose.yaml"or OO00000OOO00OOOO0 =="docker-compose.yam"or OO00000OOO00OOOO0 =="docker-compose.yml":#line:539
|
||||
if "/www/server/panel/data/compose"in OO0O0OO00OO0OO000 :#line:540
|
||||
continue #line:541
|
||||
O000O00O0OOO0O0OO .append (OO0O0OO00OO0OO000 )#line:542
|
||||
return O000O00O0OOO0O0OO #line:543
|
||||
def get_compose_project (OOO000O00OO000OO0 ,O0OOOO0OOOOO0000O ):#line:546
|
||||
""#line:552
|
||||
O0O0OO00OO0000O0O =list ()#line:553
|
||||
if O0OOOO0OOOOO0000O .path =="/":#line:554
|
||||
return public .return_msg_gettext (False ,"Can't start scanning from root directory!")#line:555
|
||||
if O0OOOO0OOOOO0000O .path [-1 ]=="/":#line:556
|
||||
O0OOOO0OOOOO0000O .path =O0OOOO0OOOOO0000O .path [:-1 ]#line:557
|
||||
if str (O0OOOO0OOOOO0000O .sub_dir )=="1":#line:558
|
||||
O000OOOO0OO00OOOO =OOO000O00OO000OO0 .scan_compose_file (O0OOOO0OOOOO0000O .path ,O0O0OO00OO0000O0O )#line:559
|
||||
if not O000OOOO0OO00OOOO :#line:560
|
||||
O000OOOO0OO00OOOO =[]#line:561
|
||||
else :#line:562
|
||||
O00O0O0OOO0OO0O00 =list ()#line:563
|
||||
for O0O00O0O0OOOO000O in O000OOOO0OO00OOOO :#line:564
|
||||
O00O0O0OOO0OO0O00 .append ({"project_name":O0O00O0O0OOOO000O .split ("/")[-2 ],"conf_file":"/".join (O0O00O0O0OOOO000O .split ("/")),"remark":"Add by local path"})#line:571
|
||||
O000OOOO0OO00OOOO =O00O0O0OOO0OO0O00 #line:572
|
||||
else :#line:573
|
||||
O00O0O00O00O0000O ="{}/docker-compose.yaml".format (O0OOOO0OOOOO0000O .path )#line:574
|
||||
OOO00OOO00O0O0OOO ="{}/docker-compose.yam".format (O0OOOO0OOOOO0000O .path )#line:575
|
||||
if os .path .exists (O00O0O00O00O0000O ):#line:576
|
||||
O000OOOO0OO00OOOO =[{"project_name":O0OOOO0OOOOO0000O .path .split ("/")[-1 ],"conf_file":O00O0O00O00O0000O ,"remark":"Add by local path"}]#line:581
|
||||
elif os .path .exists (OOO00OOO00O0O0OOO ):#line:582
|
||||
O000OOOO0OO00OOOO =[{"project_name":O0OOOO0OOOOO0000O .path .split ("/")[-1 ],"conf_file":OOO00OOO00O0O0OOO ,"remark":"Add by local path"}]#line:587
|
||||
else :#line:588
|
||||
O000OOOO0OO00OOOO =list ()#line:589
|
||||
return O000OOOO0OO00OOOO #line:591
|
||||
def add_template_in_path (O0O00000O0OO00OO0 ,OOO0OO0OO0O00O00O ):#line:594
|
||||
""#line:599
|
||||
OO0O000OO000O0OO0 =dict ()#line:600
|
||||
OO00OOO00000OOOOO =dict ()#line:601
|
||||
for OO0OO0OOO00O0OO00 in OOO0OO0OO0O00O00O .template_list :#line:602
|
||||
O0O0OO00O00O00000 =OO0OO0OOO00O0OO00 ['conf_file']#line:603
|
||||
O00O000OOOO0O00OO =OO0OO0OOO00O0OO00 ['project_name']#line:604
|
||||
OOOOO00O00O0O0OO0 =OO0OO0OOO00O0OO00 ['remark']#line:605
|
||||
O00O0O0O000O00O00 =O0O00000O0OO00OO0 .template_list (OOO0OO0OO0O00O00O )['msg']['template']#line:606
|
||||
for O00O0O0OOO0O0OOOO in O00O0O0O000O00O00 :#line:607
|
||||
if O00O000OOOO0O00OO ==O00O0O0OOO0O0OOOO ['name']:#line:608
|
||||
OO0O000OO000O0OO0 [O00O000OOOO0O00OO ]="Template already exists!"#line:609
|
||||
continue #line:610
|
||||
if not os .path .exists (O0O0OO00O00O00000 ):#line:612
|
||||
OO0O000OO000O0OO0 [O00O000OOOO0O00OO ]="The template was not found!"#line:613
|
||||
continue #line:614
|
||||
O000O0O0OOO00000O =O0O00000O0OO00OO0 .check_conf (O0O0OO00O00O00000 )#line:616
|
||||
if not O000O0O0OOO00000O ['status']:#line:617
|
||||
OO0O000OO000O0OO0 [O00O000OOOO0O00OO ]="Template validation failed, possibly malformed!"#line:618
|
||||
continue #line:619
|
||||
OO0OOO0OOOOO0O00O ={"name":O00O000OOOO0O00OO ,"remark":OOOOO00O00O0O0OO0 ,"path":O0O0OO00O00O00000 ,"add_in_path":1 }#line:626
|
||||
print (OO0OOO0OOOOO0O00O )#line:627
|
||||
dp .sql ("templates").insert (OO0OOO0OOOOO0O00O )#line:628
|
||||
OO00OOO00000OOOOO [O00O000OOOO0O00OO ]="Template added successfully!"#line:629
|
||||
print (OO0O000OO000O0OO0 )#line:631
|
||||
for O00O0O0OOO0O0OOOO in OO0O000OO000O0OO0 :#line:632
|
||||
if O00O0O0OOO0O0OOOO in OO00OOO00000OOOOO :#line:633
|
||||
del (OO00OOO00000OOOOO [O00O0O0OOO0O0OOOO ])#line:634
|
||||
else :#line:635
|
||||
dp .write_log ("Add template [{}] from path successfully!".format (O00O0O0OOO0O0OOOO ))#line:636
|
||||
if not OO0O000OO000O0OO0 and OO00OOO00000OOOOO :#line:637
|
||||
return {'status':True ,'msg':'Add template successfully: [{}]'.format (','.join (OO00OOO00000OOOOO ))}#line:638
|
||||
elif not OO00OOO00000OOOOO and OO0O000OO000O0OO0 :#line:639
|
||||
return {'status':True ,'msg':'Failed to add template: template name already exists or format validation error [{}]'.format (','.join (OO0O000OO000O0OO0 ))}#line:640
|
||||
return {'status':True ,'msg':'Add template successfully: [{}]<br>Add template failed: template name already exists or format validation error [{}]'.format (','.join (OO00OOO00000OOOOO ),','.join (OO0O000OO000O0OO0 ))}#line:641
|
||||
473
class/projectModel/bt_docker/dk_container.py
Normal file
473
class/projectModel/bt_docker/dk_container.py
Normal file
@@ -0,0 +1,473 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import public
|
||||
import docker.errors
|
||||
import projectModel.bt_docker.dk_public as dp
|
||||
class main:
|
||||
|
||||
def __init__(self):
|
||||
self.alter_table()
|
||||
|
||||
def alter_table(self):
|
||||
if not dp.sql('sqlite_master').where('type=? AND name=? AND sql LIKE ?',
|
||||
('table', 'container', '%sid%')).count():
|
||||
dp.sql('container').execute("alter TABLE container add container_name VARCHAR DEFAULT ''", ())
|
||||
|
||||
def docker_client(self,url):
|
||||
return dp.docker_client(url)
|
||||
|
||||
# 添加容器
|
||||
def run(self,args):
|
||||
"""
|
||||
:param name:容器名
|
||||
:param image: 镜像
|
||||
:param publish_all_ports 暴露所有端口 1/0
|
||||
:param ports 暴露某些端口 {'1111/tcp': ('127.0.0.1', 1111)}
|
||||
:param command 命令
|
||||
:param entrypoint 配置容器启动后执行的命令
|
||||
:param environment 环境变量 xxx=xxx 一行一条
|
||||
:param auto_remove 当容器进程退出时,在守护进程端启用自动移除容器。 0/1
|
||||
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if not hasattr(args,'ports'):
|
||||
args.ports = False
|
||||
if not hasattr(args,'volumes'):
|
||||
args.volumes = False
|
||||
#检测端口是否已经在使用
|
||||
if args.ports:
|
||||
for i in args.ports:
|
||||
if dp.check_socket(args.ports[i]):
|
||||
return public.returnMsg(False,"The server port [{}] has been used, please replace it with another port!".format(args.ports[i]))
|
||||
if not args.image:
|
||||
return public.returnMsg(False, "If there is no image selected, please go to the image tab to pull the image you need!")
|
||||
if args.restart_policy['Name'] == "always":
|
||||
args.restart_policy = {"Name":"always"}
|
||||
# return args.restart_policy
|
||||
# if
|
||||
args.cpu_quota = float(args.cpuset_cpus) * 100000
|
||||
# if not args.volumes:
|
||||
# args.volumes = {"/sys/fs/cgroup":{"bind":"/sys/fs/cgroup","mode":"rw"}}
|
||||
# else:
|
||||
# if not "/sys/fs/cgroup" in args.volumes:
|
||||
# args.volumes['/sys/fs/cgroup'] = {"bind":"/sys/fs/cgroup","mode":"rw"}
|
||||
try:
|
||||
if not args.name:
|
||||
args.name = "{}-{}".format(args.image,public.GetRandomString(8))
|
||||
if int(args.cpu_quota) / 100000 > dp.get_cpu_count():
|
||||
return public.returnMsg(False,"The CPU quota has exceeded the number of cores available!")
|
||||
mem_limit_byte = dp.byte_conversion(args.mem_limit)
|
||||
if mem_limit_byte > dp.get_mem_info():
|
||||
return public.returnMsg(False, "The memory quota has exceeded the available number!")
|
||||
res = self.docker_client(args.url).containers.run(
|
||||
name=args.name,
|
||||
image=args.image,
|
||||
detach=True,
|
||||
publish_all_ports=True if args.publish_all_ports == "1" else False,
|
||||
ports=args.ports if args.ports else None,
|
||||
command=args.command,
|
||||
auto_remove=True if str(args.auto_remove) == "1" else False,
|
||||
environment=dp.set_kv(args.environment), #"HOME=/value\nHOME11=value1"
|
||||
volumes=args.volumes, #一个字典对象 {'服务器路径/home/user1/': {'bind': '容器路径/mnt/vol2', 'mode': 'rw'},'/var/www': {'bind': '/mnt/vol1', 'mode': 'ro'}}
|
||||
# cpuset_cpus=args.cpuset_cpus ,#指定容器使用的cpu个数
|
||||
cpu_quota=int(args.cpu_quota),
|
||||
mem_limit=args.mem_limit, #b,k,m,g
|
||||
restart_policy=args.restart_policy,
|
||||
labels=dp.set_kv(args.labels), #"key=value\nkey1=value1"
|
||||
tty=True,
|
||||
stdin_open=True,
|
||||
privileged=True
|
||||
|
||||
)
|
||||
if res:
|
||||
pdata = {
|
||||
"cpu_limit": str(args.cpu_quota),
|
||||
"container_name": args.name
|
||||
}
|
||||
dp.sql('container').insert(pdata)
|
||||
public.set_module_logs('docker', 'run_container', 1)
|
||||
dp.write_log("Create container [{}] successful!".format(args.name))
|
||||
return public.returnMsg(True,"The container was created successfully!")
|
||||
return public.returnMsg(False, 'Create failed!')
|
||||
except docker.errors.APIError as e:
|
||||
if "container to be able to reuse that name." in str(e):
|
||||
return public.returnMsg(False, "The container name already exists!")
|
||||
if "Invalid container name" in str(e):
|
||||
return public.returnMsg(False, "The container name is illegal, please do not use Chinese container name!")
|
||||
if "bind: address already in use" in str(e):
|
||||
port = ""
|
||||
for i in args.ports:
|
||||
if ":{}:".format(args.ports[i]) in str(e):
|
||||
port = args.ports[i]
|
||||
args.id = args.name
|
||||
self.del_container(args)
|
||||
return public.returnMsg(False, "Server port {} is in use! Please change other ports".format(port))
|
||||
return public.returnMsg(False, 'Create failed! {}'.format(public.get_error_info()))
|
||||
|
||||
# 保存为镜像
|
||||
def commit(self,args):
|
||||
"""
|
||||
:param repository 推送到的仓库
|
||||
:param tag 镜像标签 jose:v1
|
||||
:param message 提交的信息
|
||||
:param author 镜像作者
|
||||
:param changes
|
||||
:param conf dict
|
||||
:param path 导出路径
|
||||
:param name 导出文件名
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if not hasattr(args,'conf') or not args.conf:
|
||||
args.conf = None
|
||||
if args.repository == "docker.io":
|
||||
args.repository = ""
|
||||
container = self.docker_client(args.url).containers.get(args.id)
|
||||
container.commit(
|
||||
repository=args.repository if args.repository else None,
|
||||
tag=args.tag if args.tag else None,
|
||||
message=args.message if args.message else None,
|
||||
author=args.author if args.author else None,
|
||||
# changes=args.changes if args.changes else None,
|
||||
conf=args.conf
|
||||
)
|
||||
if hasattr(args,"path") and args.path:
|
||||
args.id = "{}:{}".format(args.name,args.tag)
|
||||
import projectModel.bt_docker.dk_image as dk
|
||||
return dk.main().save(args)
|
||||
dp.write_log("Submitting container [{}] as image [{}] succeeded!".format(container.attrs['Name'],args.tag))
|
||||
return public.returnMsg(True,"提交成功!")
|
||||
|
||||
# 容器执行命令
|
||||
def docker_shell(self, args):
|
||||
"""
|
||||
:param container_id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
self.docker_client(args.url).containers.get(args.container_id)
|
||||
cmd = 'docker container exec -it {} /bin/bash'.format(args.container_id)
|
||||
return public.returnMsg(True, cmd)
|
||||
except docker.errors.APIError as ex:
|
||||
return public.returnMsg(False, 'Failed to get container')
|
||||
|
||||
# 导出容器为tar 没有导入方法,目前弃用
|
||||
def export(self,args):
|
||||
"""
|
||||
:param path 保存路径
|
||||
:param name 包名
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
from os import path as ospath
|
||||
from os import makedirs as makedirs
|
||||
try:
|
||||
if "tar" in args.name:
|
||||
file_name = '{}/{}'.format(args.path,args.name)
|
||||
else:
|
||||
file_name = '{}/{}.tar'.format(args.path, args.name)
|
||||
if not ospath.exists(args.path):
|
||||
makedirs(args.path)
|
||||
public.writeFile(file_name,'')
|
||||
f = open(file_name, 'wb')
|
||||
container = self.docker_client(args.url).containers.get(args.id)
|
||||
data = container.export()
|
||||
for i in data:
|
||||
f.write(i)
|
||||
f.close()
|
||||
return public.returnMsg(True, "Successfully exported to: {}".format(file_name))
|
||||
except:
|
||||
return public.returnMsg(False, 'Operation failed:' + str(public.get_error_info()))
|
||||
|
||||
# 删除容器
|
||||
def del_container(self,args):
|
||||
"""
|
||||
:return:
|
||||
"""
|
||||
import projectModel.bt_docker.dk_public as dp
|
||||
container = self.docker_client(args.url).containers.get(args.id)
|
||||
container.remove(force=True)
|
||||
dp.sql("cpu_stats").where("container_id=?", (args.id,)).delete()
|
||||
dp.sql("io_stats").where("container_id=?", (args.id,)).delete()
|
||||
dp.sql("mem_stats").where("container_id=?", (args.id,)).delete()
|
||||
dp.sql("net_stats").where("container_id=?", (args.id,)).delete()
|
||||
dp.sql("container").where("container_nam=?", (container.attrs['Name'])).delete()
|
||||
dp.write_log("Delete container [{}] succeeded!".format(container.attrs['Name']))
|
||||
return public.returnMsg(True,"Successfully deleted!")
|
||||
|
||||
# 设置容器状态
|
||||
def set_container_status(self,args):
|
||||
import time
|
||||
container = self.docker_client(args.url).containers.get(args.id)
|
||||
if args.act == "start":
|
||||
container.start()
|
||||
elif args.act == "stop":
|
||||
container.stop()
|
||||
elif args.act == "pause":
|
||||
container.pause()
|
||||
elif args.act == "unpause":
|
||||
container.unpause()
|
||||
elif args.act == "reload":
|
||||
container.reload()
|
||||
else:
|
||||
container.restart()
|
||||
time.sleep(1)
|
||||
tmp = self.docker_client(args.url).containers.get(args.id)
|
||||
return {"name":container.attrs['Name'].replace('/',''),"status":tmp.attrs['State']['Status']} #返回设置后的状态
|
||||
|
||||
|
||||
# 停止容器
|
||||
def stop(self,args):
|
||||
"""
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
args.act = "stop"
|
||||
data = self.set_container_status(args)
|
||||
if data['status'] != "exited":
|
||||
return public.returnMsg(False, "Stop failing!")
|
||||
dp.write_log("Stop container [{}] succeeded!".format(data['name']))
|
||||
return public.returnMsg(True, "Stop success!")
|
||||
except docker.errors.APIError as e:
|
||||
if "is already paused" in str(e):
|
||||
return public.returnMsg(False,"The container has been suspended!")
|
||||
if "No such container" in str(e):
|
||||
return public.returnMsg(True, "The container has been stopped and deleted because the container has the option to automatically delete after stopping!")
|
||||
return public.returnMsg(False,"Stop failing!{}".format(e))
|
||||
|
||||
def start(self,args):
|
||||
"""
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
args.act = "start"
|
||||
data = self.set_container_status(args)
|
||||
if data['status'] != "running":
|
||||
return public.returnMsg(False, "Startup failed!")
|
||||
dp.write_log("Start the container [{}] successfully!".format(data['name']))
|
||||
return public.returnMsg(True, "Started successfully!")
|
||||
except docker.errors.APIError as e:
|
||||
if "cannot start a paused container, try unpause instead" in str(e):
|
||||
return self.unpause(args)
|
||||
|
||||
def pause(self,args):
|
||||
"""
|
||||
Pauses all processes within this container.
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
args.act = "pause"
|
||||
data = self.set_container_status(args)
|
||||
if data['status'] != "paused":
|
||||
return public.returnMsg(False, "Container pause failed!")
|
||||
dp.write_log("Suspended container [{}] succeeded!".format(data['name']))
|
||||
return public.returnMsg(True, "Container paused successfully!")
|
||||
except docker.errors.APIError as e:
|
||||
if "is already paused" in str(e):
|
||||
return public.returnMsg(False,"The container has been suspended!")
|
||||
if "is not running" in str(e):
|
||||
return public.returnMsg(False, "The container is not started and cannot be paused!")
|
||||
if "is not paused" in str(e):
|
||||
return public.returnMsg(False, "The container has not been suspended!")
|
||||
return str(e)
|
||||
|
||||
def unpause(self,args):
|
||||
"""
|
||||
unPauses all processes within this container.
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
args.act = "unpause"
|
||||
data = self.set_container_status(args)
|
||||
if data['status'] != "running":
|
||||
return public.returnMsg(False, "Startup failed!")
|
||||
dp.write_log("Unpausing the container [{}] succeeded!".format(data['name']))
|
||||
return public.returnMsg(True, "Container unpause succeeded!")
|
||||
except docker.errors.APIError as e:
|
||||
if "is already paused" in str(e):
|
||||
return public.returnMsg(False,"The container has been suspended!")
|
||||
if "is not running" in str(e):
|
||||
return public.returnMsg(False, "The container is not started and cannot be paused!")
|
||||
if "is not paused" in str(e):
|
||||
return public.returnMsg(False, "The container has not been suspended!")
|
||||
return str(e)
|
||||
|
||||
def reload(self,args):
|
||||
"""
|
||||
Load this object from the server again and update attrs with the new data.
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
args.act = "reload"
|
||||
data = self.set_container_status(args)
|
||||
if data['status'] != "running":
|
||||
return public.returnMsg(False, "Startup failed!")
|
||||
dp.write_log("Reloading container [{}] succeeded!".format(data['name']))
|
||||
return public.returnMsg(True, "Container reload succeeded!")
|
||||
|
||||
def restart(self,args):
|
||||
"""
|
||||
Restart this container. Similar to the docker restart command.
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
args.act = "restart"
|
||||
data = self.set_container_status(args)
|
||||
if data['status'] != "running":
|
||||
return public.returnMsg(False, "Startup failed!")
|
||||
dp.write_log("Restarting the container [{}] succeeded!".format(data['name']))
|
||||
return public.returnMsg(True, "The container restarted successfully!")
|
||||
|
||||
def get_container_ip(self,container_networks):
|
||||
data = list()
|
||||
for network in container_networks:
|
||||
data.append(container_networks[network]['IPAddress'])
|
||||
return data
|
||||
|
||||
def get_container_path(self,detail):
|
||||
import os
|
||||
if not "GraphDriver" in detail:
|
||||
return False
|
||||
if "Data" not in detail["GraphDriver"]:
|
||||
return False
|
||||
if "MergedDir" not in detail["GraphDriver"]["Data"]:
|
||||
return False
|
||||
path = detail["GraphDriver"]["Data"]["MergedDir"]
|
||||
if not os.path.exists(path):
|
||||
return ""
|
||||
return path
|
||||
|
||||
# 获取容器列表所需的外部数据
|
||||
def get_other_data_for_container_list(self,args):
|
||||
import projectModel.bt_docker.dk_image as di
|
||||
import projectModel.bt_docker.dk_volume as dv
|
||||
import projectModel.bt_docker.dk_compose as dc
|
||||
import projectModel.bt_docker.dk_setup as ds
|
||||
# 获取镜像列表
|
||||
images = di.main().image_list(args)
|
||||
if images['status']:
|
||||
images = images['msg']['images_list']
|
||||
else:
|
||||
images = list()
|
||||
# 获取卷列表
|
||||
volumes = dv.main().get_volume_list(args)
|
||||
if volumes['status']:
|
||||
volumes = volumes['msg']['volume']
|
||||
else:
|
||||
volumes = list()
|
||||
# 获取模板列表
|
||||
template = dc.main().template_list(args)
|
||||
if template['status']:
|
||||
template = template['msg']['template']
|
||||
else:
|
||||
template = list()
|
||||
online_cpus = dp.get_cpu_count()
|
||||
mem_total = dp.get_mem_info()
|
||||
docker_setup = ds.main()
|
||||
return {
|
||||
"images":images,
|
||||
"volumes":volumes,
|
||||
"template":template,
|
||||
"online_cpus":online_cpus,
|
||||
"mem_total":mem_total,
|
||||
"installed":docker_setup.check_docker_program(),
|
||||
"service_status":docker_setup.get_service_status()
|
||||
}
|
||||
|
||||
# 获取容器列表
|
||||
def get_list(self,args):
|
||||
"""
|
||||
:param url
|
||||
:return:
|
||||
"""
|
||||
# 判断docker是否安装
|
||||
import projectModel.bt_docker.dk_setup as ds
|
||||
data = self.get_other_data_for_container_list(args)
|
||||
if not ds.main().check_docker_program():
|
||||
data['container_list'] = list()
|
||||
return public.returnMsg(True,data)
|
||||
client = self.docker_client(args.url)
|
||||
if not client:
|
||||
|
||||
return public.returnMsg(True,data)
|
||||
containers = client.containers
|
||||
attr_list = self.get_container_attr(containers)
|
||||
# data = self.get_other_data_for_container_list(args)
|
||||
container_detail = list()
|
||||
for attr in attr_list:
|
||||
cpu_usage = dp.sql("cpu_stats").where("container_id=?",(attr["Id"],)).select()
|
||||
if cpu_usage and isinstance(cpu_usage,list):
|
||||
cpu_usage = cpu_usage[-1]['cpu_usage']
|
||||
else:
|
||||
cpu_usage = "0.0"
|
||||
tmp = {
|
||||
"id": attr["Id"],
|
||||
"name": attr['Name'].replace("/",""),
|
||||
"status": attr["State"]["Status"],
|
||||
"image": attr["Config"]["Image"],
|
||||
"time": attr["Created"],
|
||||
"merged": self.get_container_path(attr),
|
||||
"ip": self.get_container_ip(attr["NetworkSettings"]['Networks']),
|
||||
"ports": attr["NetworkSettings"]["Ports"],
|
||||
"detail": attr,
|
||||
"cpu_usage":cpu_usage if attr["State"]["Status"] == "running" else ""
|
||||
}
|
||||
container_detail.append(tmp)
|
||||
data['container_list'] = container_detail
|
||||
return public.returnMsg(True,data)
|
||||
|
||||
# 获取容器的attr
|
||||
def get_container_attr(self,containers):
|
||||
c_list = containers.list(all=True)
|
||||
return [container_info.attrs for container_info in c_list]
|
||||
|
||||
# 获取容器日志
|
||||
def get_logs(self,args):
|
||||
"""
|
||||
:param url
|
||||
:param id
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
container = self.docker_client(args.url).containers.get(args.id)
|
||||
res = container.logs().decode()
|
||||
return public.returnMsg(True,res)
|
||||
except docker.errors.APIError as e:
|
||||
if "configured logging driver does not support reading" in str(e):
|
||||
return public.returnMsg(False,"The container has no log files!")
|
||||
|
||||
|
||||
|
||||
# 登录容器
|
||||
|
||||
|
||||
# 获取容器配置文件
|
||||
42
class/projectModel/bt_docker/dk_host.py
Normal file
42
class/projectModel/bt_docker/dk_host.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# Docker模型
|
||||
# ------------------------------
|
||||
import public #line:1
|
||||
import projectModel .bt_docker .dk_public as dp #line:2
|
||||
class main :#line:4
|
||||
def get_list (O0000O0OOO0OO0O00 ,args =None ):#line:7
|
||||
OO000O0OOO00OO00O =dp .sql ("hosts").select ()#line:8
|
||||
for OO0000O00OOO0OOO0 in OO000O0OOO00OO00O :#line:9
|
||||
if dp .docker_client (OO0000O00OOO0OOO0 ['url']):#line:10
|
||||
OO0000O00OOO0OOO0 ['status']=True #line:11
|
||||
else :#line:12
|
||||
OO0000O00OOO0OOO0 ['status']=False #line:13
|
||||
return OO000O0OOO00OO00O #line:14
|
||||
def add (O0OO00O0O000O0000 ,O00O0000O00000O0O ):#line:17
|
||||
""#line:22
|
||||
import time #line:23
|
||||
O00OO0OOO000OO0O0 =O0OO00O0O000O0000 .get_list ()#line:24
|
||||
for O0O0OO00O00OOOOOO in O00OO0OOO000OO0O0 :#line:25
|
||||
if O0O0OO00O00OOOOOO ['url']==O00O0000O00000O0O .url :#line:26
|
||||
return public .returnMsg (False ,"This host already exists!")#line:27
|
||||
if not dp .docker_client (O00O0000O00000O0O .url ):#line:29
|
||||
return public .returnMsg (False ,"Failed to connect to the server, please check if docker has been started!")#line:30
|
||||
O0O0OO0OOOOO0OOO0 ={"url":O00O0000O00000O0O .url ,"remark":O00O0000O00000O0O .remark ,"time":int (time .time ())}#line:35
|
||||
dp .write_log ("Add host [{}] successful!".format (O00O0000O00000O0O .url ))#line:36
|
||||
dp .sql ('hosts').insert (O0O0OO0OOOOO0OOO0 )#line:37
|
||||
return public .returnMsg (True ,"Add docker host successfully!")#line:38
|
||||
def delete (O0OOOO0000000O00O ,O0O0O0O000000OOOO ):#line:40
|
||||
""#line:44
|
||||
OOO00OO0OO0OOO00O =dp .sql ('hosts').where ('id=?',O0O0O0O000000OOOO (O0O0O0O000000OOOO .id ,)).find ()#line:45
|
||||
dp .sql ('hosts').delete (id =O0O0O0O000000OOOO .id )#line:46
|
||||
dp .write_log ("Delete host [{}] succeeded!".format (OOO00OO0OO0OOO00O ['url']))#line:47
|
||||
return public .returnMsg (True ,"Delete host successfully!")
|
||||
226
class/projectModel/bt_docker/dk_image.py
Normal file
226
class/projectModel/bt_docker/dk_image.py
Normal file
@@ -0,0 +1,226 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import os #line:13
|
||||
import public #line:14
|
||||
import docker .errors #line:15
|
||||
import projectModel .bt_docker .dk_public as dp #line:16
|
||||
class main :#line:18
|
||||
__O000O000OOOO0OO00 ='/tmp/dockertmp.log'#line:19
|
||||
def docker_client (O0O0OOO00O0000O0O ,OOOO0O000O000OO00 ):#line:20
|
||||
import projectModel .bt_docker .dk_public as dp #line:21
|
||||
return dp .docker_client (OOOO0O000O000OO00 )#line:22
|
||||
def save (O0O000OO0O0O00OO0 ,OOOO0000OO0O0OOOO ):#line:25
|
||||
""#line:33
|
||||
try :#line:34
|
||||
if "tar"in OOOO0000OO0O0OOOO .name :#line:35
|
||||
O00OOOO00OO0OO0OO ='{}/{}'.format (OOOO0000OO0O0OOOO .path ,OOOO0000OO0O0OOOO .name )#line:36
|
||||
else :#line:37
|
||||
O00OOOO00OO0OO0OO ='{}/{}.tar'.format (OOOO0000OO0O0OOOO .path ,OOOO0000OO0O0OOOO .name )#line:38
|
||||
if not os .path .exists (OOOO0000OO0O0OOOO .path ):#line:39
|
||||
os .makedirs (OOOO0000OO0O0OOOO .path )#line:40
|
||||
public .writeFile (O00OOOO00OO0OO0OO ,"")#line:41
|
||||
O0000O0OOOOO000OO =open (O00OOOO00OO0OO0OO ,'wb')#line:42
|
||||
O000OOOOOO00OOO00 =O0O000OO0O0O00OO0 .docker_client (OOOO0000OO0O0OOOO .url ).images .get (OOOO0000OO0O0OOOO .id )#line:43
|
||||
for OO0O0O0O0O0OO0OOO in O000OOOOOO00OOO00 .save (named =True ):#line:44
|
||||
O0000O0OOOOO000OO .write (OO0O0O0O0O0OO0OOO )#line:45
|
||||
O0000O0OOOOO000OO .close ()#line:46
|
||||
dp .write_log ("Image [{}] exported to [{}] successfully!".format (OOOO0000OO0O0OOOO .id ,O00OOOO00OO0OO0OO ))#line:47
|
||||
return public .returnMsg (True ,"Saved successfully to: {}".format (O00OOOO00OO0OO0OO ))#line:48
|
||||
except docker .errors .APIError as OOOO000OOO0O000O0 :#line:49
|
||||
if "empty export - not implemented"in str (OOOO000OOO0O000O0 ):#line:50
|
||||
return public .returnMsg (False ,"Empty images cannot be exported!")#line:51
|
||||
return public .get_error_info ()#line:52
|
||||
def load (OOO000O000OOOOOO0 ,O00OO0OOOO000O000 ):#line:55
|
||||
""#line:60
|
||||
OOOOO000O000O0000 =OOO000O000OOOOOO0 .docker_client (O00OO0OOOO000O000 .url ).images #line:61
|
||||
with open (O00OO0OOOO000O000 .path ,'rb')as OO00O0O00000000O0 :#line:62
|
||||
OOOOO000O000O0000 .load (OO00O0O00000000O0 )#line:65
|
||||
dp .write_log ("Image [{}] imported successfully!".format (O00OO0OOOO000O000 .path ))#line:66
|
||||
return public .returnMsg (True ,"Import successful! {}".format (O00OO0OOOO000O000 .path ))#line:67
|
||||
def image_list (OO0O0OOO0OOOOO00O ,OO0O0OO000O0OOOOO ):#line:70
|
||||
""#line:75
|
||||
import projectModel .bt_docker .dk_registry as dr #line:76
|
||||
import projectModel .bt_docker .dk_setup as ds #line:77
|
||||
OOO00000OOO00000O =list ()#line:78
|
||||
OO0OO00OOOO0O0O00 =OO0O0OOO0OOOOO00O .docker_client (OO0O0OO000O0OOOOO .url )#line:79
|
||||
OO0OOO00OOO0O0OO0 =ds .main ()#line:80
|
||||
O0OO0000O0O0O00O0 =OO0OOO00OOO0O0OO0 .check_docker_program ()#line:81
|
||||
O00OOO0000OO0O0OO =OO0OOO00OOO0O0OO0 .get_service_status ()#line:82
|
||||
if not OO0OO00OOOO0O0O00 :#line:83
|
||||
OOO00000OOO00000O ={"images_list":[],"registry_list":[],"installed":O0OO0000O0O0O00O0 ,"service_status":O00OOO0000OO0O0OO }#line:89
|
||||
return public .returnMsg (True ,OOO00000OOO00000O )#line:90
|
||||
OOOO000O0OO00O00O =OO0OO00OOOO0O0O00 .images #line:91
|
||||
OO0OO0OO000OOO000 =OO0O0OOO0OOOOO00O .get_image_attr (OOOO000O0OO00O00O )#line:92
|
||||
OO000O0OO000O0000 =dr .main ().registry_list (OO0O0OO000O0OOOOO )#line:93
|
||||
if OO000O0OO000O0000 ['status']:#line:94
|
||||
OO000O0OO000O0000 =OO000O0OO000O0000 ['msg']['registry']#line:95
|
||||
else :#line:96
|
||||
OO000O0OO000O0000 =[]#line:97
|
||||
for OO0O0O000000O00O0 in OO0OO0OO000OOO000 :#line:98
|
||||
if len (OO0O0O000000O00O0 ['RepoTags'])==1 :#line:99
|
||||
O0O0O0O0000OO0O00 ={"id":OO0O0O000000O00O0 ["Id"],"tags":OO0O0O000000O00O0 ["RepoTags"],"time":OO0O0O000000O00O0 ["Created"],"name":OO0O0O000000O00O0 ['RepoTags'][0 ],"size":OO0O0O000000O00O0 ["Size"],"detail":OO0O0O000000O00O0 }#line:107
|
||||
OOO00000OOO00000O .append (O0O0O0O0000OO0O00 )#line:108
|
||||
elif len (OO0O0O000000O00O0 ['RepoTags'])>1 :#line:109
|
||||
for O0OO0O0O00O000O0O in range (len (OO0O0O000000O00O0 ['RepoTags'])):#line:110
|
||||
O0O0O0O0000OO0O00 ={"id":OO0O0O000000O00O0 ["Id"],"tags":OO0O0O000000O00O0 ["RepoTags"],"time":OO0O0O000000O00O0 ["Created"],"name":OO0O0O000000O00O0 ['RepoTags'][O0OO0O0O00O000O0O ],"size":OO0O0O000000O00O0 ["Size"],"detail":OO0O0O000000O00O0 }#line:118
|
||||
OOO00000OOO00000O .append (O0O0O0O0000OO0O00 )#line:119
|
||||
elif not OO0O0O000000O00O0 ['RepoTags']:#line:120
|
||||
O0O0O0O0000OO0O00 ={"id":OO0O0O000000O00O0 ["Id"],"tags":OO0O0O000000O00O0 ["RepoTags"],"time":OO0O0O000000O00O0 ["Created"],"name":OO0O0O000000O00O0 ["Id"],"size":OO0O0O000000O00O0 ["Size"],"detail":OO0O0O000000O00O0 }#line:128
|
||||
OOO00000OOO00000O .append (O0O0O0O0000OO0O00 )#line:129
|
||||
OOO00000OOO00000O ={"images_list":OOO00000OOO00000O ,"registry_list":OO000O0OO000O0000 ,"installed":O0OO0000O0O0O00O0 ,"service_status":O00OOO0000OO0O0OO }#line:135
|
||||
return public .returnMsg (True ,OOO00000OOO00000O )#line:136
|
||||
def get_image_attr (O00OOOO0O00OOO00O ,O000O00OOOOOOO000 ):#line:138
|
||||
OOO00O0O00OO00OO0 =O000O00OOOOOOO000 .list ()#line:139
|
||||
return [OO0000OOO0OO0O0OO .attrs for OO0000OOO0OO0O0OO in OOO00O0O00OO00OO0 ]#line:140
|
||||
def get_logs (OO000O0O000000O0O ,OOOO000000O000O0O ):#line:142
|
||||
import files #line:143
|
||||
O0O0O0O0O0OOOOOO0 =OOOO000000O000O0O .logs_file #line:144
|
||||
return public .returnMsg (True ,files .files ().GetLastLine (O0O0O0O0O0OOOOOO0 ,20 ))#line:145
|
||||
def build (OOOO0OOO00O000O0O ,O00O0OOO00O00O0O0 ):#line:148
|
||||
""#line:156
|
||||
public .writeFile (OOOO0OOO00O000O0O .__O000O000OOOO0OO00 ,"Start building images!")#line:157
|
||||
public .writeFile ('/tmp/dockertmp.log',"Start building the mirror")#line:158
|
||||
if not hasattr (O00O0OOO00O00O0O0 ,"pull"):#line:159
|
||||
O00O0OOO00O00O0O0 .pull =False #line:160
|
||||
if hasattr (O00O0OOO00O00O0O0 ,"data")and O00O0OOO00O00O0O0 .data :#line:161
|
||||
O00O0OOO00O00O0O0 .path ="/tmp/dockerfile"#line:162
|
||||
public .writeFile (O00O0OOO00O00O0O0 .path ,O00O0OOO00O00O0O0 .data )#line:163
|
||||
with open (O00O0OOO00O00O0O0 .path ,'rb')as OOO000000O000OOOO :#line:164
|
||||
OO000OOOO0O0OO0O0 ,O000OOO0O0OOOO00O =OOOO0OOO00O000O0O .docker_client (O00O0OOO00O00O0O0 .url ).images .build (pull =True if O00O0OOO00O00O0O0 .pull =="1"else False ,fileobj =OOO000000O000OOOO ,tag =O00O0OOO00O00O0O0 .tag )#line:169
|
||||
os .remove (O00O0OOO00O00O0O0 .path )#line:170
|
||||
else :#line:171
|
||||
if not os .path .isdir (O00O0OOO00O00O0O0 .path ):#line:172
|
||||
O00O0OOO00O00O0O0 .path ='/'.join (O00O0OOO00O00O0O0 .path .split ('/')[:-1 ])#line:173
|
||||
OO000OOOO0O0OO0O0 ,O000OOO0O0OOOO00O =OOOO0OOO00O000O0O .docker_client (O00O0OOO00O00O0O0 .url ).images .build (pull =True if O00O0OOO00O00O0O0 .pull =="1"else False ,path =O00O0OOO00O00O0O0 .path ,tag =O00O0OOO00O00O0O0 .tag )#line:178
|
||||
dp .log_docker (O000OOO0O0OOOO00O ,"Docker build tasks")#line:180
|
||||
dp .write_log ("Building image [{}] succeeded!".format (O00O0OOO00O00O0O0 .tag ))#line:181
|
||||
return public .returnMsg (True ,"Building image successfully!")#line:182
|
||||
def remove (OOOOO00000OO0OO0O ,O0000O000000OOO00 ):#line:185
|
||||
""#line:193
|
||||
try :#line:194
|
||||
OOOOO00000OO0OO0O .docker_client (O0000O000000OOO00 .url ).images .remove (O0000O000000OOO00 .name )#line:195
|
||||
dp .write_log ("Delete mirror【{}】successful!".format (O0000O000000OOO00 .name ))#line:196
|
||||
return public .returnMsg (True ,"Mirror deleted successfully!")#line:197
|
||||
except docker .errors .ImageNotFound as OOO00OOOO00OOO0O0 :#line:198
|
||||
return public .returnMsg (False ,"Failed to delete the mirror, maybe the mirror does not exist!")#line:199
|
||||
except docker .errors .APIError as OOO00OOOO00OOO0O0 :#line:200
|
||||
if "image is referenced in multiple repositories"in str (OOO00OOOO00OOO0O0 ):#line:201
|
||||
return public .returnMsg (False ,"The image ID is used in multiple images, please check [Force Delete]!")#line:202
|
||||
if "using its referenced image"in str (OOO00OOOO00OOO0O0 ):#line:203
|
||||
return public .returnMsg (False ,"The image is in use, please delete the container and then delete it!")#line:204
|
||||
return public .returnMsg (False ,"Delete mirror failed!<br> {}".format (OOO00OOOO00OOO0O0 ))#line:205
|
||||
def pull_from_some_registry (O00OOOOOOOOO00000 ,O0O0O0OOO0O0OO0O0 ):#line:208
|
||||
""#line:215
|
||||
import projectModel .bt_docker .dk_registry as br #line:216
|
||||
O00O00OO00OOOOO00 =br .main ().registry_info (O0O0O0OOO0O0OO0O0 .name )#line:217
|
||||
O0000OO00OO0OO000 =br .main ().login (O0O0O0OOO0O0OO0O0 .url ,O00O00OO00OOOOO00 ['url'],O00O00OO00OOOOO00 ['username'],O00O00OO00OOOOO00 ['password'])['status']#line:218
|
||||
if not O0000OO00OO0OO000 :#line:219
|
||||
return O0000OO00OO0OO000 #line:220
|
||||
O0O0O0OOO0O0OO0O0 .username =O00O00OO00OOOOO00 ['username']#line:221
|
||||
O0O0O0OOO0O0OO0O0 .password =O00O00OO00OOOOO00 ['password']#line:222
|
||||
O0O0O0OOO0O0OO0O0 .registry =O00O00OO00OOOOO00 ['url']#line:223
|
||||
O0O0O0OOO0O0OO0O0 .namespace =O00O00OO00OOOOO00 ['namespace']#line:224
|
||||
return O00OOOOOOOOO00000 .pull (O0O0O0OOO0O0OO0O0 )#line:225
|
||||
def push (OO0O0OOO0O0O00O0O ,OO000OOO0OO000O0O ):#line:228
|
||||
""#line:236
|
||||
if "/"in OO000OOO0OO000O0O .tag :#line:237
|
||||
return public .returnMsg (False ,"The pushed image name cannot contain the symbol [/] , please use the following format: image:v1 (image_name:version_number)")#line:238
|
||||
if ":"not in OO000OOO0OO000O0O .tag :#line:239
|
||||
return public .returnMsg (False ,"The pushed image name must contain the symbol [ : ] , please use the following format: image:v1 (image_name:version_number)")#line:240
|
||||
public .writeFile (OO0O0OOO0O0O00O0O .__O000O000OOOO0OO00 ,"Start pushing mirrors!\n")#line:241
|
||||
import projectModel .bt_docker .dk_registry as br #line:242
|
||||
O00O0O0O0O0O0O000 =br .main ().registry_info (OO000OOO0OO000O0O .name )#line:243
|
||||
if OO000OOO0OO000O0O .name =="docker official"and O00O0O0O0O0O0O000 ['url']=="docker.io":#line:244
|
||||
public .writeFile (OO0O0OOO0O0O00O0O .__O000O000OOOO0OO00 ,"The image cannot be pushed to the Docker public repository!\n")#line:245
|
||||
return public .returnMsg (False ,"Unable to push to Docker public repo!")#line:246
|
||||
O0O0000OOO0OOO00O =br .main ().login (OO000OOO0OO000O0O .url ,O00O0O0O0O0O0O000 ['url'],O00O0O0O0O0O0O000 ['username'],O00O0O0O0O0O0O000 ['password'])['status']#line:247
|
||||
O00OOO0O0O0O0O0O0 =OO000OOO0OO000O0O .tag #line:248
|
||||
if not O0O0000OOO0OOO00O :#line:249
|
||||
return O0O0000OOO0OOO00O #line:250
|
||||
OO00O0000000OO000 ={"username":O00O0O0O0O0O0O000 ['username'],"password":O00O0O0O0O0O0O000 ['password'],"registry":O00O0O0O0O0O0O000 ['url']}#line:254
|
||||
if ":"not in O00OOO0O0O0O0O0O0 :#line:256
|
||||
O00OOO0O0O0O0O0O0 ="{}:latest".format (O00OOO0O0O0O0O0O0 )#line:257
|
||||
OOOO000OOOOO0O00O =O00O0O0O0O0O0O000 ['url']#line:258
|
||||
O0OO00O0OO000O0OO ="{}/{}/{}".format (OOOO000OOOOO0O00O ,O00O0O0O0O0O0O000 ['namespace'],OO000OOO0OO000O0O .tag )#line:259
|
||||
OO0O0OOO0O0O00O0O .tag (OO000OOO0OO000O0O .url ,OO000OOO0OO000O0O .id ,O0OO00O0OO000O0OO )#line:260
|
||||
O000OOOO00O0OO000 =OO0O0OOO0O0O00O0O .docker_client (OO000OOO0OO000O0O .url ).images .push (repository =O0OO00O0OO000O0OO .split (":")[0 ],tag =O00OOO0O0O0O0O0O0 .split (":")[-1 ],auth_config =OO00O0000000OO000 ,stream =True )#line:266
|
||||
dp .log_docker (O000OOOO00O0OO000 ,"Image push task")#line:267
|
||||
OO000OOO0OO000O0O .name =O0OO00O0OO000O0OO #line:269
|
||||
OO0O0OOO0O0O00O0O .remove (OO000OOO0OO000O0O )#line:270
|
||||
dp .write_log ("The image [{}] was pushed successfully!".format (O0OO00O0OO000O0OO ))#line:271
|
||||
return public .returnMsg (True ,"推送成功!{}".format (str (O000OOOO00O0OO000 )))#line:272
|
||||
def tag (OOO0OO00OO0OO0O00 ,O000O0OOO00O000OO ,OOOO0O0OOO0000O00 ,OO0O0000OO00O00O0 ):#line:274
|
||||
""#line:281
|
||||
OOO000O000000OOO0 =OO0O0000OO00O00O0 .split (":")[0 ]#line:282
|
||||
O00OOO0OOOO0O000O =OO0O0000OO00O00O0 .split (":")[1 ]#line:283
|
||||
OOO0OO00OO0OO0O00 .docker_client (O000O0OOO00O000OO ).images .get (OOOO0O0OOO0000O00 ).tag (repository =OOO000O000000OOO0 ,tag =O00OOO0OOOO0O000O )#line:287
|
||||
return public .returnMsg (True ,"Set successfully")#line:288
|
||||
def pull (O0O0O0000OOOOOOO0 ,OO00OOO00OO000O00 ):#line:290
|
||||
""#line:299
|
||||
public .writeFile (O0O0O0000OOOOOOO0 .__O000O000OOOO0OO00 ,"Start pulling images!")#line:300
|
||||
import docker .errors #line:301
|
||||
try :#line:302
|
||||
if ':'not in OO00OOO00OO000O00 .image :#line:303
|
||||
OO00OOO00OO000O00 .image ='{}:latest'.format (OO00OOO00OO000O00 .image )#line:304
|
||||
O0O00OO000O000OO0 ={"username":OO00OOO00OO000O00 .username ,"password":OO00OOO00OO000O00 .password ,"registry":OO00OOO00OO000O00 .registry if OO00OOO00OO000O00 .registry else None }if OO00OOO00OO000O00 .username else None #line:308
|
||||
if not hasattr (OO00OOO00OO000O00 ,"tag"):#line:309
|
||||
OO00OOO00OO000O00 .tag =OO00OOO00OO000O00 .image .split (":")[-1 ]#line:310
|
||||
if OO00OOO00OO000O00 .registry !="docker.io":#line:311
|
||||
OO00OOO00OO000O00 .image ="{}/{}/{}".format (OO00OOO00OO000O00 .registry ,OO00OOO00OO000O00 .namespace ,OO00OOO00OO000O00 .image )#line:312
|
||||
OOO0OOOO000O000O0 =dp .docker_client_low (OO00OOO00OO000O00 .url ).pull (repository =OO00OOO00OO000O00 .image ,auth_config =O0O00OO000O000OO0 ,tag =OO00OOO00OO000O00 .tag ,stream =True )#line:318
|
||||
dp .log_docker (OOO0OOOO000O000O0 ,"Image pull task")#line:319
|
||||
if OOO0OOOO000O000O0 :#line:320
|
||||
dp .write_log ("The image [{}:{}] was pulled successfully!".format (OO00OOO00OO000O00 .image ,OO00OOO00OO000O00 .tag ))#line:321
|
||||
return public .returnMsg (True ,'Pulling the image succeeded.')#line:322
|
||||
else :#line:323
|
||||
return public .returnMsg (False ,'There may not be this image.')#line:324
|
||||
except docker .errors .ImageNotFound as O0O0OO00OO000O0O0 :#line:325
|
||||
if "pull access denied for"in str (O0O0OO00OO000O0O0 ):#line:326
|
||||
return public .returnMsg (False ,"The pull failed, the image is a private image, you need to enter the account password of dockerhub!")#line:327
|
||||
return public .returnMsg (False ,"Pull failed<br><br>reasons: {}".format (O0O0OO00OO000O0O0 ))#line:329
|
||||
except docker .errors .NotFound as O0O0OO00OO000O0O0 :#line:331
|
||||
if "not found: manifest unknown"in str (O0O0OO00OO000O0O0 ):#line:332
|
||||
return public .returnMsg (False ,"The pull failed, the repository does not have the mirror!")#line:333
|
||||
return public .returnMsg (False ,"Pull failed<br><br>reason:{}".format (O0O0OO00OO000O0O0 ))#line:334
|
||||
except docker .errors .APIError as O0O0OO00OO000O0O0 :#line:335
|
||||
if "invalid tag format"in str (O0O0OO00OO000O0O0 ):#line:336
|
||||
return public .returnMsg (False ,"The pull failed, the image format is wrong, the format should be: nginx:v 1!")#line:337
|
||||
return public .returnMsg (False ,"Pull failed!{}".format (O0O0OO00OO000O0O0 ))#line:338
|
||||
def pull_high_api (OO0O0O0O000O000O0 ,O0000O0O000O0O0O0 ):#line:342
|
||||
""#line:351
|
||||
import docker .errors #line:352
|
||||
try :#line:353
|
||||
if ':'not in O0000O0O000O0O0O0 .image :#line:354
|
||||
O0000O0O000O0O0O0 .image ='{}:latest'.format (O0000O0O000O0O0O0 .image )#line:355
|
||||
O0O0O00O0O0O00000 ={"username":O0000O0O000O0O0O0 .username ,"password":O0000O0O000O0O0O0 .password ,"registry":O0000O0O000O0O0O0 .registry if O0000O0O000O0O0O0 .registry else None }if O0000O0O000O0O0O0 .username else None #line:359
|
||||
if O0000O0O000O0O0O0 .registry !="docker.io":#line:361
|
||||
O0000O0O000O0O0O0 .image ="{}/{}/{}".format (O0000O0O000O0O0O0 .registry ,O0000O0O000O0O0O0 .namespace ,O0000O0O000O0O0O0 .image )#line:362
|
||||
OOOOOOOO0O0OOOO0O =OO0O0O0O000O000O0 .docker_client (O0000O0O000O0O0O0 .url ).images .pull (repository =O0000O0O000O0O0O0 .image ,auth_config =O0O0O00O0O0O00000 ,)#line:366
|
||||
if OOOOOOOO0O0OOOO0O :#line:367
|
||||
return public .returnMsg (True ,'Pulling the image succeeded.')#line:368
|
||||
else :#line:369
|
||||
return public .returnMsg (False ,'There may not be this mirror.')#line:370
|
||||
except docker .errors .ImageNotFound as O0O0O0OOO0O0OO0OO :#line:371
|
||||
if "pull access denied for"in str (O0O0O0OOO0O0OO0OO ):#line:372
|
||||
return public .returnMsg (False ,"The pull failed, the image is a private image, you need to enter the account password of dockerhub!")#line:373
|
||||
return public .returnMsg (False ,"Pull failed<br><br>reason: {}".format (O0O0O0OOO0O0OO0OO ))#line:374
|
||||
def image_for_host (O00O0O0O000OOO0O0 ,O000OO0OOOOO000O0 ):#line:376
|
||||
""#line:381
|
||||
O00O000OO0OO000OO =O00O0O0O000OOO0O0 .image_list (O000OO0OOOOO000O0 )#line:382
|
||||
if not O00O000OO0OO000OO ['status']:#line:383
|
||||
return O00O000OO0OO000OO #line:384
|
||||
OO000O0000O000000 =len (O00O000OO0OO000OO ['msg']['images_list'])#line:385
|
||||
O0OOOO0OO000OO0OO =0 #line:386
|
||||
for OO00OOO0000OO0O00 in O00O000OO0OO000OO ['msg']['images_list']:#line:387
|
||||
O0OOOO0OO000OO0OO +=OO00OOO0000OO0O00 ['size']#line:388
|
||||
return public .returnMsg (True ,{'num':OO000O0000O000000 ,'size':O0OOOO0OO000OO0OO })
|
||||
92
class/projectModel/bt_docker/dk_monitor.py
Normal file
92
class/projectModel/bt_docker/dk_monitor.py
Normal file
@@ -0,0 +1,92 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import sys #line:1
|
||||
import threading #line:2
|
||||
sys .path .insert (0 ,"/www/server/panel/class/")#line:3
|
||||
sys .path .insert (1 ,"/www/server/panel/")#line:4
|
||||
import projectModel .bt_docker .dk_public as dp #line:5
|
||||
import projectModel .bt_docker .dk_container as dc #line:6
|
||||
import projectModel .bt_docker .dk_status as ds #line:7
|
||||
import projectModel .bt_docker .dk_image as di #line:8
|
||||
import public #line:9
|
||||
import time #line:11
|
||||
class main :#line:12
|
||||
__OOOOO0OOO0OO00O00 =None #line:14
|
||||
__OOOOOO0OO0OOOOOO0 =86400 #line:15
|
||||
def __init__ (O00O000000O0OO0OO ,OO00OO00O0O00OO0O ):#line:17
|
||||
if not OO00OO00O0O00OO0O :#line:18
|
||||
O00O000000O0OO0OO .__OOOOO0OOO0OO00O00 =30 #line:19
|
||||
else :#line:20
|
||||
O00O000000O0OO0OO .__OOOOO0OOO0OO00O00 =OO00OO00O0O00OO0O #line:21
|
||||
def docker_client (OOOOO000OO0O00OO0 ,OO00OOO0000OO0000 ):#line:23
|
||||
return dp .docker_client (OO00OOO0000OO0000 )#line:24
|
||||
def get_all_host_stats (O0000O0000OO0O000 ,O000O0O00OO00O00O ):#line:26
|
||||
""#line:31
|
||||
OO000O0OO0O0O0000 =dp .sql ('hosts').select ()#line:32
|
||||
for O00O0OO00O0O000O0 in OO000O0OO0O0O0000 :#line:33
|
||||
O0OO00O0O00O0000O =threading .Thread (target =O000O0O00OO00O00O ,args =(O00O0OO00O0O000O0 ,))#line:34
|
||||
O0OO00O0O00O0000O .setDaemon (True )#line:35
|
||||
O0OO00O0O00O0000O .start ()#line:36
|
||||
def container_status_for_all_hosts (OO0O00OO0O0OOOO0O ,OOOOOOO000OO0OOO0 ):#line:39
|
||||
""#line:44
|
||||
O000OO000O0O00O00 =public .to_dict_obj ({})#line:46
|
||||
O000OO000O0O00O00 .url =OOOOOOO000OO0OOO0 ['url']#line:47
|
||||
O0O0O0O000O00O0OO =dc .main ().get_list (O000OO000O0O00O00 )['msg']#line:48
|
||||
for O00OOOOOOOO00OOO0 in O0O0O0O000O00O0OO ['container_list']:#line:49
|
||||
O000OO000O0O00O00 .id =O00OOOOOOOO00OOO0 ['id']#line:50
|
||||
O000OO000O0O00O00 .write =1 #line:51
|
||||
O000OO000O0O00O00 .save_date =OO0O00OO0O0OOOO0O .__OOOOO0OOO0OO00O00 #line:52
|
||||
ds .main ().stats (O000OO000O0O00O00 )#line:53
|
||||
def container_count (OO0000O0O0O0OOO00 ):#line:57
|
||||
O0O000O0O000O000O =dp .sql ('hosts').select ()#line:59
|
||||
O0O00O00O0O00OOO0 =0 #line:60
|
||||
for O0O0O00OO0OO0O0O0 in O0O000O0O000O000O :#line:61
|
||||
O00OOOO00OO0OOO00 =public .to_dict_obj ({})#line:62
|
||||
O00OOOO00OO0OOO00 .url =O0O0O00OO0OO0O0O0 ['url']#line:63
|
||||
OO00OO00O0O00O00O =dc .main ().get_list (O00OOOO00OO0OOO00 )['msg']#line:64
|
||||
O0O00O00O0O00OOO0 +=len (OO00OO00O0O00O00O )#line:65
|
||||
O0000000000000000 ={"time":int (time .time ()),"container_count":O0O00O00O0O00OOO0 }#line:69
|
||||
OOOOO0OO00OOO0O0O =time .time ()-(OO0000O0O0O0OOO00 .__OOOOO0OOO0OO00O00 *OO0000O0O0O0OOO00 .__OOOOOO0OO0OOOOOO0 )#line:70
|
||||
dp .sql ("container_count").where ("time<?",(OOOOO0OO00OOO0O0O ,)).delete ()#line:71
|
||||
dp .sql ("container_count").insert (O0000000000000000 )#line:72
|
||||
def image_for_all_host (OO0O00O000OO00O0O ):#line:75
|
||||
OO000OO0OOO00OO0O =dp .sql ('hosts').select ()#line:77
|
||||
OOO0OOO00O000OOOO =0 #line:78
|
||||
O0O00000OO0O0O000 =0 #line:79
|
||||
for O00OOO00O0000O00O in OO000OO0OOO00OO0O :#line:80
|
||||
O0O00O0OOOO0O00O0 =public .to_dict_obj ({})#line:81
|
||||
O0O00O0OOOO0O00O0 .url =O00OOO00O0000O00O ['url']#line:82
|
||||
OO00O0000O0000O00 =di .main ().image_for_host (O0O00O0OOOO0O00O0 )#line:83
|
||||
if not OO00O0000O0000O00 ['status']:#line:84
|
||||
continue #line:85
|
||||
print (OO00O0000O0000O00 )#line:86
|
||||
OOO0OOO00O000OOOO +=OO00O0000O0000O00 ['msg']['num']#line:87
|
||||
O0O00000OO0O0O000 +=OO00O0000O0000O00 ['msg']['size']#line:88
|
||||
O0OO0O00O000000OO ={"time":int (time .time ()),"num":OOO0OOO00O000OOOO ,"size":int (O0O00000OO0O0O000 )}#line:93
|
||||
O0O000O00OO0OO0O0 =time .time ()-(OO0O00O000OO00O0O .__OOOOO0OOO0OO00O00 *OO0O00O000OO00O0O .__OOOOOO0OO0OOOOOO0 )#line:94
|
||||
dp .sql ("image_infos").where ("time<?",(O0O000O00OO0OO0O0 ,)).delete ()#line:95
|
||||
dp .sql ("image_infos").insert (O0OO0O00O000000OO )#line:96
|
||||
def monitor ():#line:99
|
||||
while True :#line:102
|
||||
O0OOO000OOO0OOO00 =dp .docker_conf ()['SAVE']#line:103
|
||||
O000OO0O0O0OO0000 =main (O0OOO000OOO0OOO00 )#line:104
|
||||
O000OO0O0O0OO0000 .get_all_host_stats (O000OO0O0O0OO0000 .container_status_for_all_hosts )#line:105
|
||||
O0000OO0000000O00 =threading .Thread (target =O000OO0O0O0OO0000 .container_count )#line:107
|
||||
O0000OO0000000O00 .setDaemon (True )#line:108
|
||||
O0000OO0000000O00 .start ()#line:109
|
||||
O0000OO0000000O00 =threading .Thread (target =O000OO0O0O0OO0000 .image_for_all_host )#line:111
|
||||
O0000OO0000000O00 .setDaemon (True )#line:112
|
||||
O0000OO0000000O00 .start ()#line:113
|
||||
time .sleep (60 )#line:114
|
||||
if __name__ =="__main__":#line:119
|
||||
monitor ()
|
||||
69
class/projectModel/bt_docker/dk_network.py
Normal file
69
class/projectModel/bt_docker/dk_network.py
Normal file
@@ -0,0 +1,69 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import public #line:1
|
||||
import projectModel .bt_docker .dk_public as dp #line:2
|
||||
import docker .errors #line:3
|
||||
class main :#line:5
|
||||
def docker_client (O00O0O000OO0000O0 ,OOO0OOOO0O0000OO0 ):#line:7
|
||||
import projectModel .bt_docker .dk_public as dp #line:8
|
||||
return dp .docker_client (OOO0OOOO0O0000OO0 )#line:9
|
||||
def get_host_network (OO0O00O000O000O0O ,O00OO00OO00OOOOOO ):#line:11
|
||||
""#line:16
|
||||
import projectModel .bt_docker .dk_setup as ds #line:17
|
||||
O00OO00O00000000O =ds .main ()#line:18
|
||||
O000O0O0O00OO000O =O00OO00O00000000O .check_docker_program ()#line:19
|
||||
O0O00O000OOO0OO0O =O00OO00O00000000O .get_service_status ()#line:20
|
||||
OO0O0O00OO0OO0OO0 =OO0O00O000O000O0O .docker_client (O00OO00OO00OOOOOO .url )#line:21
|
||||
if not OO0O0O00OO0OO0OO0 :#line:22
|
||||
O0000O0000O0O0OO0 ={"images_list":[],"registry_list":[],"installed":O000O0O0O00OO000O ,"service_status":O0O00O000OOO0OO0O }#line:28
|
||||
return public .returnMsg (True ,O0000O0000O0O0OO0 )#line:29
|
||||
O000OO0OO00OOOO0O =OO0O0O00OO0OO0OO0 .networks #line:30
|
||||
O0OOO0O00O00OO000 =OO0O00O000O000O0O .get_network_attr (O000OO0OO00OOOO0O )#line:31
|
||||
O0000O0000O0O0OO0 =list ()#line:32
|
||||
for OOOO0O0OOOO0O00O0 in O0OOO0O00O00OO000 :#line:33
|
||||
OOOO00OOOO0O0000O =""#line:34
|
||||
O00O000OOOO000O0O =""#line:35
|
||||
if OOOO0O0OOOO0O00O0 ["IPAM"]["Config"]:#line:36
|
||||
if "Subnet"in OOOO0O0OOOO0O00O0 ["IPAM"]["Config"][0 ]:#line:37
|
||||
OOOO00OOOO0O0000O =OOOO0O0OOOO0O00O0 ["IPAM"]["Config"][0 ]["Subnet"]#line:38
|
||||
if "Gateway"in OOOO0O0OOOO0O00O0 ["IPAM"]["Config"][0 ]:#line:39
|
||||
O00O000OOOO000O0O =OOOO0O0OOOO0O00O0 ["IPAM"]["Config"][0 ]["Gateway"]#line:40
|
||||
OOOOO000000OO000O ={"id":OOOO0O0OOOO0O00O0 ["Id"],"name":OOOO0O0OOOO0O00O0 ["Name"],"time":OOOO0O0OOOO0O00O0 ["Created"],"driver":OOOO0O0OOOO0O00O0 ["IPAM"]["Driver"],"subnet":OOOO00OOOO0O0000O ,"gateway":O00O000OOOO000O0O ,"labels":OOOO0O0OOOO0O00O0 ["Labels"]}#line:49
|
||||
O0000O0000O0O0OO0 .append (OOOOO000000OO000O )#line:50
|
||||
OOOOOOO000O0O0O0O ={"network":O0000O0000O0O0OO0 ,"installed":O000O0O0O00OO000O ,"service_status":O0O00O000OOO0OO0O }#line:56
|
||||
return public .returnMsg (True ,OOOOOOO000O0O0O0O )#line:57
|
||||
def get_network_attr (OO0O00O00O000OO00 ,O0OO0000O0OOO0O0O ):#line:59
|
||||
O000OOOO0OOO00O00 =O0OO0000O0OOO0O0O .list ()#line:60
|
||||
return [O00O0000O0OO00O00 .attrs for O00O0000O0OO00O00 in O000OOOO0OOO00O00 ]#line:61
|
||||
def add (O0OOO0O0O0000OO0O ,O0OOO0O000000000O ):#line:63
|
||||
""#line:75
|
||||
import docker #line:76
|
||||
O0O0000OO00OO00OO =docker .types .IPAMPool (subnet =O0OOO0O000000000O .subnet ,gateway =O0OOO0O000000000O .gateway ,iprange =O0OOO0O000000000O .iprange )#line:81
|
||||
OOOO00000O000OO0O =docker .types .IPAMConfig (pool_configs =[O0O0000OO00OO00OO ])#line:84
|
||||
O0OOO0O0O0000OO0O .docker_client (O0OOO0O000000000O .url ).networks .create (name =O0OOO0O000000000O .name ,options =O0OOO0O000000000O .options if O0OOO0O000000000O .options else None ,driver ="bridge",ipam =OOOO00000O000OO0O ,labels =dp .set_kv (O0OOO0O000000000O .labels ))#line:91
|
||||
dp .write_log ("Add network [{}] [{}] successful!".format (O0OOO0O000000000O .name ,O0OOO0O000000000O .iprange ))#line:92
|
||||
return public .returnMsg (True ,"Added successfully!")#line:93
|
||||
def del_network (OOOOO0OO0O00O000O ,OOO0OOOO0O0O0O0O0 ):#line:95
|
||||
""#line:100
|
||||
try :#line:101
|
||||
O000O0OO00O0OO000 =OOOOO0OO0O00O000O .docker_client (OOO0OOOO0O0O0O0O0 .url ).networks .get (OOO0OOOO0O0O0O0O0 .id )#line:103
|
||||
O0OOOOOO0OO0O0OOO =O000O0OO00O0OO000 .attrs #line:104
|
||||
if O0OOOOOO0OO0O0OOO ['Name']in ["bridge","none"]:#line:105
|
||||
return public .returnMsg (False ,"The system default network cannot be deleted!")#line:106
|
||||
O000O0OO00O0OO000 .remove ()#line:107
|
||||
dp .write_log ("Delete network [{}] successful!".format (O0OOOOOO0OO0O0OOO ['Name']))#line:108
|
||||
return public .returnMsg (True ,"Successfully deleted!")#line:109
|
||||
except docker .errors .APIError as OOOOOO0O00O0O0OO0 :#line:110
|
||||
if " has active endpoints"in str (OOOOOO0O00O0O0OO0 ):#line:111
|
||||
return public .returnMsg (False ,"The network is in use and cannot be deleted!")#line:112
|
||||
return public .returnMsg (False ,"Failed to delete! {}".format (str (OOOOOO0O00O0O0OO0 )))
|
||||
135
class/projectModel/bt_docker/dk_public.py
Normal file
135
class/projectModel/bt_docker/dk_public.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
|
||||
import db #line:1
|
||||
import public #line:2
|
||||
import json #line:3
|
||||
def sql (O000O0O0O00000OO0 ):#line:5
|
||||
with db .Sql ()as O000000OOO00O0000 :#line:6
|
||||
O000000OOO00O0000 .dbfile ("docker")#line:7
|
||||
return O000000OOO00O0000 .table (O000O0O0O00000OO0 )#line:8
|
||||
def docker_client (url ="unix:///var/run/docker.sock"):#line:11
|
||||
import docker #line:12
|
||||
"""
|
||||
目前仅支持本地服务器
|
||||
:param url: unix:///var/run/docker.sock
|
||||
:return:
|
||||
"""#line:17
|
||||
try :#line:18
|
||||
O00O00O00000OO0OO =docker .DockerClient (base_url =url )#line:19
|
||||
O00O00O00000OO0OO .networks .list ()#line:20
|
||||
return O00O00O00000OO0OO #line:21
|
||||
except :#line:22
|
||||
return False #line:23
|
||||
def docker_client_low (url ="unix:///var/run/docker.sock"):#line:25
|
||||
""#line:30
|
||||
import docker #line:31
|
||||
try :#line:32
|
||||
O0OO0000000O0OOOO =docker .APIClient (base_url =url )#line:33
|
||||
return O0OO0000000O0OOOO #line:34
|
||||
except docker .errors .DockerException :#line:35
|
||||
return False #line:36
|
||||
def get_cpu_count ():#line:39
|
||||
import re #line:40
|
||||
OOO00O00O0000O00O =open ('/proc/cpuinfo','r').read ()#line:41
|
||||
OO00O0000OO000OOO =r"processor\s*:"#line:42
|
||||
OO0OOO0O00O0O0OOO =re .findall (OO00O0000OO000OOO ,OOO00O00O0000O00O )#line:43
|
||||
if not OO0OOO0O00O0O0OOO :#line:44
|
||||
return 0 #line:45
|
||||
return len (OO0OOO0O00O0O0OOO )#line:46
|
||||
def set_kv (OO0OO0OOO0O00O0OO ):#line:48
|
||||
""#line:53
|
||||
if not OO0OO0OOO0O00O0OO :#line:54
|
||||
return None #line:55
|
||||
O00OOOOO0O0OOOO00 =OO0OO0OOO0O00O0OO .split ('\n')#line:56
|
||||
O000OOO0OO00O00OO =dict ()#line:57
|
||||
for OOOOO0OO00OO0O0OO in O00OOOOO0O0OOOO00 :#line:58
|
||||
OOOOO0OO00OO0O0OO =OOOOO0OO00OO0O0OO .strip ()#line:59
|
||||
if not OOOOO0OO00OO0O0OO :#line:60
|
||||
continue #line:61
|
||||
OOO00OO000O000000 ,OO00O0O00000OOO00 =OOOOO0OO00OO0O0OO .split ('=')#line:62
|
||||
O000OOO0OO00O00OO [OOO00OO000O000000 ]=OO00O0O00000OOO00 #line:63
|
||||
return O000OOO0OO00O00OO #line:64
|
||||
def get_mem_info ():#line:66
|
||||
import psutil #line:68
|
||||
O0O0OOO000OO0OOO0 =psutil .virtual_memory ()#line:69
|
||||
O00OOO0O0O00O0O0O =int (O0O0OOO000OO0OOO0 .total )#line:70
|
||||
return O00OOO0O0O00O0O0O #line:71
|
||||
def byte_conversion (OO000000O00OOO0O0 ):#line:73
|
||||
if "b"in OO000000O00OOO0O0 :#line:74
|
||||
return int (OO000000O00OOO0O0 .replace ('b',''))#line:75
|
||||
elif "KB"in OO000000O00OOO0O0 :#line:76
|
||||
return int (OO000000O00OOO0O0 .replace ('KB',''))*1024 #line:77
|
||||
elif "MB"in OO000000O00OOO0O0 :#line:78
|
||||
return int (OO000000O00OOO0O0 .replace ('MB',''))*1024 *1024 #line:79
|
||||
elif "GB"in OO000000O00OOO0O0 :#line:80
|
||||
return int (OO000000O00OOO0O0 .replace ('GB',''))*1024 *1024 *1024 #line:81
|
||||
else :#line:82
|
||||
return False #line:83
|
||||
def log_docker (OO000O00O0OOO0000 ,O0OO0O0O0O0OOO0O0 ):#line:85
|
||||
__OO0000000OO0OO0O0 ='/tmp/dockertmp.log'#line:86
|
||||
while True :#line:87
|
||||
try :#line:88
|
||||
O000O0OOOOO0OOOO0 =OO000O00O0OOO0000 .__next__ ()#line:89
|
||||
try :#line:90
|
||||
O000O0OOOOO0OOOO0 =json .loads (O000O0OOOOO0OOOO0 )#line:91
|
||||
if 'status'in O000O0OOOOO0OOOO0 :#line:92
|
||||
O0OOO00OO0O0OO00O ="{}\n".format (O000O0OOOOO0OOOO0 ['status'])#line:93
|
||||
public .writeFile (__OO0000000OO0OO0O0 ,O0OOO00OO0O0OO00O ,'a+')#line:94
|
||||
except :#line:95
|
||||
public .writeFile (__OO0000000OO0OO0O0 ,public .get_error_info (),'a+')#line:96
|
||||
if 'stream'in O000O0OOOOO0OOOO0 :#line:97
|
||||
O0OOO00OO0O0OO00O =O000O0OOOOO0OOOO0 ['stream']#line:98
|
||||
public .writeFile (__OO0000000OO0OO0O0 ,O0OOO00OO0O0OO00O ,'a+')#line:99
|
||||
except StopIteration :#line:100
|
||||
public .writeFile (__OO0000000OO0OO0O0 ,f'{O0OO0O0O0O0OOO0O0} complete.','a+')#line:101
|
||||
break #line:102
|
||||
except ValueError :#line:103
|
||||
public .writeFile (log_path ,f'Error parsing output from {O0OO0O0O0O0OOO0O0}: {O000O0OOOOO0OOOO0}','a+')#line:104
|
||||
def docker_conf ():#line:106
|
||||
""#line:112
|
||||
OO0OOO0000OO0000O =public .readFile ("{}/data/docker.conf".format (public .get_panel_path ()))#line:113
|
||||
if not OO0OOO0000OO0000O :#line:114
|
||||
return {"SAVE":30 }#line:115
|
||||
O0O0OOOO0000OO0OO =dict ()#line:116
|
||||
for OO0OOO0O0OOO000O0 in OO0OOO0000OO0000O .split ("\n"):#line:117
|
||||
if not OO0OOO0O0OOO000O0 :#line:118
|
||||
continue #line:119
|
||||
O0OOO00O0O0OOOO00 ,OOOO00O0OOO00O00O =OO0OOO0O0OOO000O0 .split ("=")#line:120
|
||||
if O0OOO00O0O0OOOO00 =="SAVE":#line:121
|
||||
OOOO00O0OOO00O00O =int (OOOO00O0OOO00O00O )#line:122
|
||||
O0O0OOOO0000OO0OO [O0OOO00O0O0OOOO00 ]=OOOO00O0OOO00O00O #line:123
|
||||
return O0O0OOOO0000OO0OO #line:124
|
||||
def get_process_id (OOOO0000O00OO00OO ,O0OO0OO0OOO0OOOOO ):#line:126
|
||||
import psutil #line:127
|
||||
OOOO000O0000OO0OO =psutil .pids ()#line:128
|
||||
for OO000O0000OOOO0O0 in OOOO000O0000OO0OO :#line:129
|
||||
try :#line:130
|
||||
O0OOO0000OOOO00O0 =psutil .Process (OO000O0000OOOO0O0 )#line:131
|
||||
if O0OOO0000OOOO00O0 .name ()==OOOO0000O00OO00OO and O0OO0OO0OOO0OOOOO in O0OOO0000OOOO00O0 .cmdline ():#line:132
|
||||
return OO000O0000OOOO0O0 #line:133
|
||||
except :#line:134
|
||||
pass #line:135
|
||||
return False #line:136
|
||||
def write_log (OOO0OO0O0O00OO0O0 ):#line:138
|
||||
public .WriteLog ("Docker module",OOO0OO0O0O00OO0O0 )#line:139
|
||||
def check_socket (O0000O0O000O0O000 ):#line:141
|
||||
import socket #line:142
|
||||
OO0O0O0OO0OO0000O =socket .socket (socket .AF_INET ,socket .SOCK_STREAM )#line:143
|
||||
O0O0OO00OOOO000O0 =("127.0.0.1",int (O0000O0O000O0O000 ))#line:144
|
||||
O000O00OO00O0000O =OO0O0O0OO0OO0000O .connect_ex (O0O0OO00OOOO000O0 )#line:145
|
||||
OO0O0O0OO0OO0000O .close ()#line:146
|
||||
if O000O00OO00O0000O ==0 :#line:147
|
||||
return True #line:148
|
||||
else :#line:149
|
||||
return False
|
||||
81
class/projectModel/bt_docker/dk_registry.py
Normal file
81
class/projectModel/bt_docker/dk_registry.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import public #line:1
|
||||
import os #line:2
|
||||
import json #line:3
|
||||
import projectModel .bt_docker .dk_public as dp #line:4
|
||||
class main :#line:6
|
||||
def docker_client (O0OOOO000OOOO0OOO ,O0OO0000O00OO0OO0 ):#line:8
|
||||
return dp .docker_client (O0OO0000O00OO0OO0 )#line:9
|
||||
def add (O0OOO0OO00OO0O0O0 ,OOO0000O0O000O0OO ):#line:11
|
||||
""#line:22
|
||||
if not OOO0000O0O000O0OO .registry :#line:24
|
||||
OOO0000O0O000O0OO .registry ="docker.io"#line:25
|
||||
O000O00O000O0O00O =O0OOO0OO00OO0O0O0 .login (OOO0000O0O000O0OO .url ,OOO0000O0O000O0OO .registry ,OOO0000O0O000O0OO .username ,OOO0000O0O000O0OO .password )#line:26
|
||||
if not O000O00O000O0O00O ['status']:#line:27
|
||||
return O000O00O000O0O00O #line:28
|
||||
O000OO0O00OO00OOO =O0OOO0OO00OO0O0O0 .registry_list ("get")['msg']['registry']#line:29
|
||||
for OOOOOOO0O000O0OOO in O000OO0O00OO00OOO :#line:30
|
||||
if OOOOOOO0O000O0OOO ['name']==OOO0000O0O000O0OO .name :#line:31
|
||||
return public .returnMsg (False ,"Name already exists! <br><br>Name: {}".format (OOO0000O0O000O0OO .name ))#line:32
|
||||
if OOOOOOO0O000O0OOO ['username']==OOO0000O0O000O0OO .username and OOO0000O0O000O0OO .registry ==OOOOOOO0O000O0OOO ['url']:#line:33
|
||||
return public .returnMsg (False ,"The repository information already exists!")#line:34
|
||||
O0OO0000OOO0OO00O ={"name":OOO0000O0O000O0OO .name ,"url":OOO0000O0O000O0OO .registry ,"namespace":OOO0000O0O000O0OO .namespace ,"username":OOO0000O0O000O0OO .username ,"password":OOO0000O0O000O0OO .password ,"remark":OOO0000O0O000O0OO .remark }#line:42
|
||||
dp .sql ("registry").insert (O0OO0000OOO0OO00O )#line:43
|
||||
dp .write_log ("Add repository [{}] [{}] successful!".format (OOO0000O0O000O0OO .name ,OOO0000O0O000O0OO .registry ))#line:44
|
||||
return public .returnMsg (True ,"Added successfully!")#line:45
|
||||
def edit (O0O0O0O000O00OOO0 ,O0O000OO000000OOO ):#line:47
|
||||
""#line:58
|
||||
if str (O0O000OO000000OOO .id )=="1":#line:60
|
||||
return public .returnMsg (False ,"[Docker official repository] cannot be edited!")#line:61
|
||||
if not O0O000OO000000OOO .registry :#line:62
|
||||
O0O000OO000000OOO .registry ="docker.io"#line:63
|
||||
O00O00O0O0O0000OO =O0O0O0O000O00OOO0 .login (O0O000OO000000OOO .url ,O0O000OO000000OOO .registry ,O0O000OO000000OOO .username ,O0O000OO000000OOO .password )#line:64
|
||||
if not O00O00O0O0O0000OO ['status']:#line:65
|
||||
return O00O00O0O0O0000OO #line:66
|
||||
O00O00O0O0O0000OO =dp .sql ("registry").where ("id=?",(O0O000OO000000OOO .id ,)).find ()#line:67
|
||||
if not O00O00O0O0O0000OO :#line:68
|
||||
return public .returnMsg (False ,"This repository was not found")#line:69
|
||||
OO0OOOOO0O000OOOO ={"name":O0O000OO000000OOO .name ,"url":O0O000OO000000OOO .registry ,"username":O0O000OO000000OOO .username ,"password":O0O000OO000000OOO .password ,"namespace":O0O000OO000000OOO .namespace ,"remark":O0O000OO000000OOO .remark }#line:77
|
||||
dp .sql ("registry").where ("id=?",(O0O000OO000000OOO .id ,)).update (OO0OOOOO0O000OOOO )#line:78
|
||||
dp .write_log ("Editing repository [{}][{}] succeeded!".format (O0O000OO000000OOO .name ,O0O000OO000000OOO .registry ))#line:79
|
||||
return public .returnMsg (True ,"Edited successfully!")#line:80
|
||||
def remove (OO0OO00O00OO0O000 ,O0O00O0OO0000OO00 ):#line:82
|
||||
""#line:88
|
||||
if str (O0O00O0OO0000OO00 .id )=="1":#line:89
|
||||
return public .returnMsg (False ,"[Docker official repository] cannot be deleted!")#line:90
|
||||
OO00O0OO00000000O =dp .sql ("registry").where ("id=?",(O0O00O0OO0000OO00 .id )).find ()#line:91
|
||||
dp .sql ("registry").where ("id=?",(O0O00O0OO0000OO00 .id ,)).delete ()#line:92
|
||||
dp .write_log ("Deleting repository [{}][{}] succeeded!".format (OO00O0OO00000000O ['name'],OO00O0OO00000000O ['url']))#line:93
|
||||
return public .returnMsg (True ,"Successfully deleted!")#line:94
|
||||
def registry_list (OO0OOOO0000O00OOO ,O000OO0O00OO0O0OO ):#line:96
|
||||
""#line:100
|
||||
import projectModel .bt_docker .dk_setup as ds #line:101
|
||||
OO0OO0000OO0O0O00 =dp .sql ("registry").select ()#line:102
|
||||
if not isinstance (OO0OO0000OO0O0O00 ,list ):#line:103
|
||||
OO0OO0000OO0O0O00 =[]#line:104
|
||||
OOOO0OO000O000O00 =ds .main ()#line:105
|
||||
OO0O0O0OOO0O0000O ={"registry":OO0OO0000OO0O0O00 ,"installed":OOOO0OO000O000O00 .check_docker_program (),"service_status":OOOO0OO000O000O00 .get_service_status ()}#line:110
|
||||
return public .returnMsg (True ,OO0O0O0OOO0O0000O )#line:111
|
||||
def registry_info (OOO0OO0O0OOOO0O00 ,O0OOO00O0O00000OO ):#line:113
|
||||
return dp .sql ("registry").where ("name=?",(O0OOO00O0O00000OO ,)).find ()#line:114
|
||||
def login (O0O0OO0O000000O00 ,OO00O00O0O0OOOOO0 ,OO0O000O000O00000 ,O0OOO000000000O00 ,O00OO0O00O000OO0O ):#line:116
|
||||
""#line:121
|
||||
import docker .errors #line:122
|
||||
try :#line:123
|
||||
O0OOO0OO00OOOOOO0 =O0O0OO0O000000O00 .docker_client (OO00O00O0O0OOOOO0 ).login (registry =OO0O000O000O00000 ,username =O0OOO000000000O00 ,password =O00OO0O00O000OO0O ,reauth =False )#line:129
|
||||
return public .returnMsg (True ,str (O0OOO0OO00OOOOOO0 ))#line:130
|
||||
except docker .errors .APIError as OOOO0OOO0O00O0000 :#line:131
|
||||
if "unauthorized: incorrect username or password"in str (OOOO0OOO0O00O0000 ):#line:132
|
||||
return public .returnMsg (False ,"Login test failed! <br><br>Reason: The account password is incorrect! {}".format (OOOO0OOO0O00O0000 ))#line:133
|
||||
return public .returnMsg (False ,"Login test failed! <br><br>Reason: {}".format (OOOO0OOO0O00O0000 ))
|
||||
67
class/projectModel/bt_docker/dk_screen.py
Normal file
67
class/projectModel/bt_docker/dk_screen.py
Normal file
@@ -0,0 +1,67 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import projectModel.bt_docker.dk_public as dp
|
||||
import time
|
||||
|
||||
class main :#line:1
|
||||
def get_status (O00OO00O00O0OO00O ,OOO0000O00O0OOO0O ):#line:3
|
||||
""#line:9
|
||||
O000OO00O0O0OOO0O =dict ()#line:10
|
||||
O000OO00O0O0OOO0O ['container_count']=O00OO00O00O0OO00O .__O0OO000000O0OO0O0 (OOO0000O00O0OOO0O )#line:12
|
||||
O000OO00O0O0OOO0O ['image_info']=dp .sql ("image_infos").where ("time>=? and time<=?",(OOO0000O00O0OOO0O .start_time ,OOO0000O00O0OOO0O .stop_time )).select ()#line:14
|
||||
O000OO00O0O0OOO0O ['host']=len (dp .sql ('hosts').select ())#line:16
|
||||
O000OO00O0O0OOO0O ['container_top']={"cpu":O00OO00O00O0OO00O .__OO0OOO00O0OOO0OOO (),"mem":O00OO00O00O0OO00O .__O0OO00OOO00O00OOO ()}#line:18
|
||||
return O000OO00O0O0OOO0O #line:19
|
||||
def __O0OO000000O0OO0O0 (OOOO0OO0O00O0OOOO ,OO0OO0OO000O00O0O ):#line:21
|
||||
O0OOO000O0OOOO0O0 =dp .sql ('container_count').where ("time>=? and time<=?",(OO0OO0OO000O00O0O .start_time ,OO0OO0OO000O00O0O .stop_time )).select ()#line:22
|
||||
if not O0OOO000O0OOOO0O0 :#line:23
|
||||
return 0 #line:24
|
||||
return O0OOO000O0OOOO0O0 [-1 ]#line:25
|
||||
def __O0OO00OOO00O00OOO (OOO0OOO0O00OOOOO0 ):#line:27
|
||||
O000OO0O00O0O00OO =int (time .time ())#line:28
|
||||
O0OO0O0OO0O00O0O0 =O000OO0O00O0O00OO -3600 #line:29
|
||||
OO0O000OO00OO0OOO =dp .sql ("mem_stats").where ("time>=? and time<=?",(O0OO0O0OO0O00O0O0 ,O000OO0O00O0O00OO )).select ()#line:30
|
||||
O000O0OO00OOOO0O0 =list ()#line:31
|
||||
O0O0O000OO00OOOOO =dict ()#line:32
|
||||
for O00OOOO0OOOO00000 in OO0O000OO00OO0OOO :#line:34
|
||||
O000O0OO00OOOO0O0 .append (O00OOOO0OOOO00000 ['container_id'])#line:35
|
||||
O000O0OO00OOOO0O0 =set (O000O0OO00OOOO0O0 )#line:37
|
||||
for OO0O0OO000OO0OO00 in O000O0OO00OOOO0O0 :#line:38
|
||||
OO0000OOOOOOOO000 =0 #line:39
|
||||
OO0000O00O000000O =0 #line:40
|
||||
for O00OOOO0OOOO00000 in OO0O000OO00OO0OOO :#line:41
|
||||
if O00OOOO0OOOO00000 ['container_id']==OO0O0OO000OO0OO00 :#line:42
|
||||
OO0000OOOOOOOO000 +=1 #line:43
|
||||
OO0000O00O000000O +=float (O00OOOO0OOOO00000 ['usage'])#line:44
|
||||
if OO0000OOOOOOOO000 !=0 :#line:45
|
||||
O0O0O000OO00OOOOO [OO0O0OO000OO0OO00 ]=OO0000O00O000000O /OO0000OOOOOOOO000 #line:46
|
||||
return O0O0O000OO00OOOOO #line:47
|
||||
def __OO0OOO00O0OOO0OOO (O0O0O0O000OOO000O ):#line:49
|
||||
O0O0OO0OO00OO0000 =int (time .time ())#line:50
|
||||
OO000OOO00OO0OOO0 =O0O0OO0OO00OO0000 -3600 #line:51
|
||||
OO000O0OOOO0OO00O =dp .sql ("cpu_stats").where ("time>=? and time<=?",(OO000OOO00OO0OOO0 ,O0O0OO0OO00OO0000 )).select ()#line:52
|
||||
OOO00O00O0OO0O0OO =list ()#line:53
|
||||
OO0OOOOOO000OO000 =dict ()#line:54
|
||||
for O0000O0O0000O0OOO in OO000O0OOOO0OO00O :#line:56
|
||||
OOO00O00O0OO0O0OO .append (O0000O0O0000O0OOO ['container_id'])#line:57
|
||||
OOO00O00O0OO0O0OO =set (OOO00O00O0OO0O0OO )#line:59
|
||||
for OO0OO00OOOOOO0O0O in OOO00O00O0OO0O0OO :#line:60
|
||||
OO00O0000000OO0OO =0 #line:61
|
||||
OO0OOOO0OOOO000O0 =0 #line:62
|
||||
for O0000O0O0000O0OOO in OO000O0OOOO0OO00O :#line:63
|
||||
if O0000O0O0000O0OOO ['container_id']==OO0OO00OOOOOO0O0O :#line:64
|
||||
OO00O0000000OO0OO +=1 #line:65
|
||||
OO0OOOO0OOOO000O0 +=float (0 if O0000O0O0000O0OOO ['cpu_usage']=='0.0'else O0000O0O0000O0OOO ['cpu_usage'])#line:66
|
||||
if OO00O0000000OO0OO !=0 :#line:67
|
||||
OO0OOOOOO000OO000 [OO0OO00OOOOOO0O0O ]=OO0OOOO0OOOO000O0 /OO00O0000000OO0OO #line:68
|
||||
return OO0OOOOOO000OO000
|
||||
156
class/projectModel/bt_docker/dk_setup.py
Normal file
156
class/projectModel/bt_docker/dk_setup.py
Normal file
@@ -0,0 +1,156 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
|
||||
import os
|
||||
import json
|
||||
import public
|
||||
import projectModel.bt_docker.dk_public as dp
|
||||
|
||||
class main :#line:1
|
||||
def get_config (O0OO0OO0O0OOO0OOO ,O0OOOO000OOOO0000 ):#line:3
|
||||
import projectModel .bt_docker .dk_public as dp #line:4
|
||||
O00O0OOO0O0O0OO00 =O0OO0OO0O0OOO0OOO .get_registry_mirrors (O0OOOO000OOOO0000 )#line:6
|
||||
if not O00O0OOO0O0O0OO00 ["status"]:#line:7
|
||||
return O00O0OOO0O0O0OO00 #line:8
|
||||
else :#line:9
|
||||
O00O0OOO0O0O0OO00 =O00O0OOO0O0O0OO00 ['msg']#line:10
|
||||
OOO00O00O00000000 =O0OO0OO0O0OOO0OOO .get_service_status ()#line:11
|
||||
return public .returnMsg (True ,{"registry_mirrors":O00O0OOO0O0O0OO00 ,"service_status":OOO00O00O00000000 ,"installed":O0OO0OO0O0OOO0OOO .check_docker_program (),"monitor_status":O0OO0OO0O0OOO0OOO .get_monitor_status (),"monitor_save_date":dp .docker_conf ()['SAVE']})#line:18
|
||||
def set_monitor_save_date (O0OO0000000O0OO0O ,OO0OO0O0O00OO0OOO ):#line:20
|
||||
""#line:25
|
||||
import re #line:26
|
||||
OOOO0O0OO00O00O00 ="{}/data/docker.conf".format (public .get_panel_path ())#line:27
|
||||
O00OO000O0OO0000O =public .readFile (OOOO0O0OO00O00O00 )#line:28
|
||||
try :#line:29
|
||||
OOO00O0000000OO0O =int (OO0OO0O0O00OO0OOO .save_date )#line:30
|
||||
except :#line:31
|
||||
return public .returnMsg (False ,"The monitoring save time needs to be a positive integer!")#line:32
|
||||
if OOO00O0000000OO0O >999 :#line:33
|
||||
return public .returnMsg (False ,"Monitoring data cannot be retained for more than 999 days!")#line:34
|
||||
if not O00OO000O0OO0000O :#line:35
|
||||
O00OO000O0OO0000O ="SAVE={}".format (OOO00O0000000OO0O )#line:36
|
||||
public .writeFile (OOOO0O0OO00O00O00 ,O00OO000O0OO0000O )#line:37
|
||||
return public .returnMsg (True ,"Set up successfully!")#line:38
|
||||
O00OO000O0OO0000O =re .sub (r"SAVE\s*=\s*\d+","SAVE={}".format (OOO00O0000000OO0O ),O00OO000O0OO0000O )#line:39
|
||||
public .writeFile (OOOO0O0OO00O00O00 ,O00OO000O0OO0000O )#line:40
|
||||
dp .write_log ("Set the monitoring time to [] days!".format (OOO00O0000000OO0O ))#line:41
|
||||
return public .returnMsg (True ,"Set up successfully!")#line:42
|
||||
def get_service_status (OO0O0OOOO00O0000O ):#line:44
|
||||
import projectModel .bt_docker .dk_public as dp #line:45
|
||||
OOOO0OO00O00O0O0O ='/var/run/docker.pid'#line:46
|
||||
if os .path .exists (OOOO0OO00O00O0O0O ):#line:47
|
||||
try :#line:48
|
||||
O0O0O0OOO0OO0OOOO =dp .docker_client ()#line:49
|
||||
if O0O0O0OOO0OO0OOOO :#line:50
|
||||
return True #line:51
|
||||
else :#line:52
|
||||
return False #line:53
|
||||
except :#line:54
|
||||
return False #line:55
|
||||
else :#line:56
|
||||
return False #line:57
|
||||
def docker_service (O00OOO000O0000O0O ,OOO00OO000000OOOO ):#line:60
|
||||
""#line:65
|
||||
import public #line:66
|
||||
O000O0OOO0O0O000O ={'start':'start','stop':'stop','restart':'restart'}#line:67
|
||||
if OOO00OO000000OOOO .act not in O000O0OOO0O0O000O :#line:68
|
||||
return public .returnMsg (False ,'There is no way to do this!')#line:69
|
||||
O0000OO0O0OOOOOO0 ='systemctl {} docker'.format (OOO00OO000000OOOO .act )#line:70
|
||||
if OOO00OO000000OOOO .act =="stop":#line:71
|
||||
O0000OO0O0OOOOOO0 +="&& systemctl {} docker.socket".format (OOO00OO000000OOOO .act )#line:72
|
||||
public .ExecShell (O0000OO0O0OOOOOO0 )#line:73
|
||||
dp .write_log ("Set the Docker service status to [{}] successful".format (O000O0OOO0O0O000O [OOO00OO000000OOOO .act ]))#line:74
|
||||
return public .returnMsg (True ,"Set the status to [{}] successful".format (O000O0OOO0O0O000O [OOO00OO000000OOOO .act ]))#line:75
|
||||
def get_registry_mirrors (O000O0OO0O00O0000 ,OO00O0OOO000O00O0 ):#line:78
|
||||
try :#line:79
|
||||
if not os .path .exists ('/etc/docker/daemon.json'):#line:80
|
||||
return public .returnMsg (True ,[])#line:81
|
||||
O00000OOOOOOOO0O0 =json .loads (public .readFile ('/etc/docker/daemon.json'))#line:82
|
||||
if "registry-mirrors"not in O00000OOOOOOOO0O0 :#line:83
|
||||
return public .returnMsg (True ,[])#line:84
|
||||
return public .returnMsg (True ,O00000OOOOOOOO0O0 ['registry-mirrors'])#line:85
|
||||
except :#line:86
|
||||
return public .returnMsg (False ,'Get failed! Reason for failure: {}'.format (public .get_error_info ()))#line:87
|
||||
def set_registry_mirrors (OO0OO0000OO0OOOO0 ,OOOO000OO0O00O000 ):#line:90
|
||||
""#line:95
|
||||
import re #line:96
|
||||
try :#line:97
|
||||
O0000O0O0O000O00O ={}#line:98
|
||||
if os .path .exists ('/etc/docker/daemon.json'):#line:99
|
||||
O0000O0O0O000O00O =json .loads (public .readFile ('/etc/docker/daemon.json'))#line:100
|
||||
if not OOOO000OO0O00O000 .registry_mirrors_address .strip ():#line:101
|
||||
if 'registry-mirrors'not in O0000O0O0O000O00O :#line:103
|
||||
return public .returnMsg (True ,'Set successfully')#line:104
|
||||
del (O0000O0O0O000O00O ['registry-mirrors'])#line:105
|
||||
else :#line:106
|
||||
O0O0O0O00OOOO0O0O =OOOO000OO0O00O000 .registry_mirrors_address .strip ().split ('\n')#line:107
|
||||
for O0000OOO0OO0000O0 in O0O0O0O00OOOO0O0O :#line:108
|
||||
if not re .search ('https?://',O0000OOO0OO0000O0 ):#line:109
|
||||
return public .returnMsg (False ,'The acceleration address [{}] is malformed<br>Reference: https://mirror.ccs.tencentyun.com'.format (O0000OOO0OO0000O0 ))#line:110
|
||||
O0000O0O0O000O00O ['registry-mirrors']=O0O0O0O00OOOO0O0O #line:112
|
||||
public .writeFile ('/etc/docker/daemon.json',json .dumps (O0000O0O0O000O00O ,indent =2 ))#line:115
|
||||
dp .write_log ("Set up Docker acceleration successfully!")#line:116
|
||||
return public .returnMsg (True ,'Set successfully')#line:117
|
||||
except :#line:118
|
||||
return public .returnMsg (False ,'Setup failed! Reason for failure:{}'.format (public .get_error_info ()))#line:119
|
||||
def get_monitor_status (OO0O00O0OO0O0O000 ):#line:121
|
||||
""#line:124
|
||||
O00O000O00OO00000 =public .process_exists ("python",cmdline ="/www/server/panel/class/projectModel/bt_docker/dk_monitor.py")#line:126
|
||||
if O00O000O00OO00000 :#line:127
|
||||
return O00O000O00OO00000 #line:128
|
||||
O00O000O00OO00000 =public .process_exists ("python3",cmdline ="/www/server/panel/class/projectModel/bt_docker/dk_monitor.py")#line:129
|
||||
if O00O000O00OO00000 :#line:130
|
||||
return O00O000O00OO00000 #line:131
|
||||
return O00O000O00OO00000 #line:132
|
||||
def set_docker_monitor (OO0OOOOOOO0O00OO0 ,O0O0O0000O0OOO000 ):#line:134
|
||||
""#line:139
|
||||
import time #line:140
|
||||
import projectModel .bt_docker .dk_public as dp #line:141
|
||||
OOO000O0O0O0OOOO0 ="/www/server/panel/pyenv/bin/python"#line:142
|
||||
if not os .path .exists (OOO000O0O0O0OOOO0 ):#line:143
|
||||
OOO000O0O0O0OOOO0 ="/www/server/panel/pyenv/bin/python3"#line:144
|
||||
O0O000O0O00O0O000 ="/www/server/panel/class/projectModel/bt_docker/dk_monitor.py"#line:145
|
||||
if O0O0O0000O0OOO000 .act =="start":#line:146
|
||||
OOO0O00OO0OO0O00O ="nohup {} {} &".format (OOO000O0O0O0OOOO0 ,O0O000O0O00O0O000 )#line:147
|
||||
public .ExecShell (OOO0O00OO0OO0O00O )#line:148
|
||||
time .sleep (1 )#line:149
|
||||
if OO0OOOOOOO0O00OO0 .get_monitor_status ():#line:150
|
||||
dp .write_log ("Docker monitoring started successfully!")#line:151
|
||||
return public .returnMsg (True ,"Start monitoring successfully!")#line:152
|
||||
return public .returnMsg (False ,"Failed to start monitoring!")#line:153
|
||||
else :#line:154
|
||||
O0O0OOOOOOOO0O0OO =dp .get_process_id ("python","/www/server/panel/class/projectModel/bt_docker/dk_monitor.py")#line:155
|
||||
if not O0O0OOOOOOOO0O0OO :#line:156
|
||||
O0O0OOOOOOOO0O0OO =dp .get_process_id ("python3","/www/server/panel/class/projectModel/bt_docker/dk_monitor.py")#line:157
|
||||
public .ExecShell ("kill -9 {}".format (O0O0OOOOOOOO0O0OO ))#line:158
|
||||
dp .write_log ("Docker monitoring stopped successfully!")#line:159
|
||||
return public .returnMsg (True ,"Stop monitoring successfully!")#line:160
|
||||
def check_docker_program (O0O00O00OOOO0O000 ):#line:162
|
||||
""#line:166
|
||||
O0O0O00O000OOO000 ="/usr/bin/docker"#line:167
|
||||
O00OO00OO0OOOOOO0 ="/usr/bin/docker-compose"#line:168
|
||||
if not os .path .exists (O0O0O00O000OOO000 )or not os .path .exists (O00OO00OO0OOOOOO0 ):#line:169
|
||||
return False #line:170
|
||||
return True #line:171
|
||||
def install_docker_program (OOO0000OOO0O0O0O0 ,O0O000O0OO000OO0O ):#line:173
|
||||
""#line:178
|
||||
import time #line:179
|
||||
O000O000O0OO00O00 ="Install Docker service"#line:180
|
||||
O00O000OOOOOOO000 ="/bin/bash /www/server/panel/install/install_soft.sh 0 install docker_install_en"#line:183
|
||||
public .M ('tasks').add ('id,name,type,status,addtime,execstr',(None ,O000O000O0OO00O00 ,'execshell','0',time .strftime ('%Y-%m-%d %H:%M:%S'),O00O000OOOOOOO000 ))#line:184
|
||||
if not public.is_self_hosted():
|
||||
public .httpPost (public .GetConfigValue ('home')+'/api/panel/plugin_total',{"pid":"1111111",'p_name':"Docker商用模块"},3 )#line:185
|
||||
public.arequests('post', '{}/api/setupCount/setupPlugin'.format(public.OfficialApiBase()),
|
||||
data={"pid": "1111111", 'p_name': "Dockerpaymodel"}, timeout=3)
|
||||
|
||||
return public .returnMsg (True ,"Install task added to queue!")#line:186
|
||||
160
class/projectModel/bt_docker/dk_status.py
Normal file
160
class/projectModel/bt_docker/dk_status.py
Normal file
@@ -0,0 +1,160 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import public #line:13
|
||||
import time #line:14
|
||||
import projectModel .bt_docker .dk_public as dp #line:15
|
||||
class main :#line:18
|
||||
__OOOO00OOO0O00O0O0 =dict ()#line:20
|
||||
__OO0O0O00OO0OOO000 =None #line:21
|
||||
def docker_client (OOOOOO000OOOO0OOO ,OO0OOO0O0O00O0000 ):#line:23
|
||||
if not OOOOOO000OOOO0OOO .__OO0O0O00OO0OOO000 :#line:24
|
||||
OOOOOO000OOOO0OOO .__OO0O0O00OO0OOO000 =dp .docker_client (OO0OOO0O0O00O0000 )#line:25
|
||||
return OOOOOO000OOOO0OOO .__OO0O0O00OO0OOO000 #line:26
|
||||
def io_stats (O00OOOOO000OO00OO ,O00O0OO0000OO0O0O ,write =None ):#line:28
|
||||
O0O0OO0OOO0OO0000 =O00O0OO0000OO0O0O ['blkio_stats']['io_service_bytes_recursive']#line:29
|
||||
if len (O0O0OO0OOO0OO0000 )<=2 :#line:30
|
||||
try :#line:31
|
||||
O0OO0OO0O000OOOOO =O0O0OO0OOO0OO0000 [0 ]['value']#line:32
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['read_total']=O0OO0OO0O000OOOOO #line:33
|
||||
except :#line:34
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['read_total']=0 #line:35
|
||||
try :#line:36
|
||||
O0OO0OO0O000OOOOO =O0O0OO0OOO0OO0000 [1 ]['value']#line:37
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['write_total']=O0OO0OO0O000OOOOO #line:38
|
||||
except :#line:39
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['write_total']=0 #line:40
|
||||
else :#line:41
|
||||
try :#line:42
|
||||
O0OO0OO0O000OOOOO =O0O0OO0OOO0OO0000 [0 ]['value']+O0O0OO0OOO0OO0000 [2 ]['value']#line:43
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['read_total']=O0OO0OO0O000OOOOO #line:44
|
||||
except :#line:45
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['read_total']=0 #line:46
|
||||
try :#line:47
|
||||
O0OO0OO0O000OOOOO =O0O0OO0OOO0OO0000 [1 ]['value']+O0O0OO0OOO0OO0000 [3 ]['value']#line:48
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['write_total']=O0OO0OO0O000OOOOO #line:49
|
||||
except :#line:50
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['write_total']=0 #line:51
|
||||
if write :#line:52
|
||||
O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 ['container_id']=O00O0OO0000OO0O0O ['id']#line:53
|
||||
O00OOOOO000OO00OO .write_io (O00OOOOO000OO00OO .__OOOO00OOO0O00O0O0 )#line:54
|
||||
def net_stats (OOO0000O0O0O00O0O ,O0O0OOO00O0000OOO ,OO0O0O000OOO000OO ,write =None ):#line:56
|
||||
try :#line:57
|
||||
OO00OOOO0O0000OOO =O0O0OOO00O0000OOO ['networks']['eth0']#line:58
|
||||
OOO00O00O0O00OOOO =OO0O0O000OOO000OO ['networks']['eth0']#line:59
|
||||
except :#line:60
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['rx_total']=0 #line:61
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['rx']=0 #line:62
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['tx_total']=0 #line:63
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['tx']=0 #line:64
|
||||
if write :#line:65
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['container_id']=O0O0OOO00O0000OOO ['id']#line:66
|
||||
OOO0000O0O0O00O0O .write_net (OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 )#line:67
|
||||
return #line:68
|
||||
O0000OO00OO0OOO00 =O0O0OOO00O0000OOO ["time"]#line:69
|
||||
O0000OO0OO0OOOOOO =OO0O0O000OOO000OO ["time"]#line:70
|
||||
try :#line:71
|
||||
O0O000O00O0OO0OO0 =OO00OOOO0O0000OOO ["rx_bytes"]#line:72
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['rx_total']=O0O000O00O0OO0OO0 #line:73
|
||||
O0000OOO0OO00OOO0 =OOO00O00O0O00OOOO ["rx_bytes"]#line:74
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['rx']=int ((O0O000O00O0OO0OO0 -O0000OOO0OO00OOO0 )/(O0000OO00OO0OOO00 -O0000OO0OO0OOOOOO ))#line:75
|
||||
except :#line:76
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['rx_total']=0 #line:77
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['rx']=0 #line:78
|
||||
try :#line:79
|
||||
O0O000O00O0OO0OO0 =OO00OOOO0O0000OOO ["tx_bytes"]#line:80
|
||||
O0000OOO0OO00OOO0 =OOO00O00O0O00OOOO ["tx_bytes"]#line:81
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['tx_total']=O0O000O00O0OO0OO0 #line:82
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['tx']=int ((O0O000O00O0OO0OO0 -O0000OOO0OO00OOO0 )/(O0000OO00OO0OOO00 -O0000OO0OO0OOOOOO ))#line:83
|
||||
except :#line:84
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['tx_total']=0 #line:85
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['tx']=0 #line:86
|
||||
if write :#line:87
|
||||
OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 ['container_id']=O0O0OOO00O0000OOO ['id']#line:88
|
||||
OOO0000O0O0O00O0O .write_net (OOO0000O0O0O00O0O .__OOOO00OOO0O00O0O0 )#line:89
|
||||
def mem_stats (O0OO000OOO0O0O000 ,O00OOO0OO00OOO000 ,write =None ):#line:92
|
||||
OOO0000OO0OOO000O =O00OOO0OO00OOO000 ['memory_stats']#line:93
|
||||
try :#line:94
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['limit']=OOO0000OO0OOO000O ['limit']#line:95
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['usage_total']=OOO0000OO0OOO000O ['usage']#line:96
|
||||
if 'cache'not in OOO0000OO0OOO000O ['stats']:#line:97
|
||||
OOO0000OO0OOO000O ['stats']['cache']=0 #line:98
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['usage']=OOO0000OO0OOO000O ['usage']-OOO0000OO0OOO000O ['stats']['cache']#line:99
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['cache']=OOO0000OO0OOO000O ['stats']['cache']#line:100
|
||||
except :#line:102
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['limit']=0 #line:104
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['usage']=0 #line:105
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['cache']=0 #line:106
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['usage_total']=0 #line:107
|
||||
if write :#line:109
|
||||
O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 ['container_id']=O00OOO0OO00OOO000 ['id']#line:110
|
||||
O0OO000OOO0O0O000 .write_mem (O0OO000OOO0O0O000 .__OOOO00OOO0O00O0O0 )#line:111
|
||||
def cpu_stats (OO0OO000OO000O000 ,OO0000OOO00OO0O0O ,write =None ):#line:114
|
||||
try :#line:120
|
||||
OOOOO0O0OO0O00O0O =OO0000OOO00OO0O0O ['cpu_stats']['cpu_usage']['total_usage']-OO0000OOO00OO0O0O ['precpu_stats']['cpu_usage']['total_usage']#line:121
|
||||
except :#line:122
|
||||
OOOOO0O0OO0O00O0O =0 #line:123
|
||||
try :#line:124
|
||||
OO00000O0O0OO0O00 =OO0000OOO00OO0O0O ['cpu_stats']['system_cpu_usage']-OO0000OOO00OO0O0O ['precpu_stats']['system_cpu_usage']#line:125
|
||||
except :#line:126
|
||||
OO00000O0O0OO0O00 =0 #line:127
|
||||
try :#line:128
|
||||
OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 ['online_cpus']=OO0000OOO00OO0O0O ['cpu_stats']['online_cpus']#line:129
|
||||
except :#line:130
|
||||
OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 ['online_cpus']=0 #line:131
|
||||
if OOOOO0O0OO0O00O0O >0 and OO00000O0O0OO0O00 >0 :#line:132
|
||||
OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 ['cpu_usage']=round ((OOOOO0O0OO0O00O0O /OO00000O0O0OO0O00 )*100 *OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 ['online_cpus'],2 )#line:133
|
||||
else :#line:134
|
||||
OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 ['cpu_usage']=0.0 #line:135
|
||||
if write :#line:136
|
||||
OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 ['container_id']=OO0000OOO00OO0O0O ['id']#line:137
|
||||
OO0OO000OO000O000 .write_cpu (OO0OO000OO000O000 .__OOOO00OOO0O00O0O0 )#line:138
|
||||
def stats (OO0OOOO00OO0OO000 ,OO00OO0OO00OOO0O0 ):#line:141
|
||||
""#line:148
|
||||
OOOOO00O00000OOO0 =OO0OOOO00OO0OO000 .docker_client (OO00OO0OO00OOO0O0 .url ).containers .get (OO00OO0OO00OOO0O0 .id )#line:149
|
||||
O00O0OOOO000O0O0O =OOOOO00O00000OOO0 .stats (decode =None ,stream =False )#line:150
|
||||
O00O0OOOO000O0O0O ['time']=time .time ()#line:151
|
||||
OOOOOOOOO0OO0O00O =public .cache_get ('stats')#line:152
|
||||
if not OOOOOOOOO0OO0O00O :#line:153
|
||||
OOOOOOOOO0OO0O00O =O00O0OOOO000O0O0O #line:154
|
||||
public .cache_set ('stats',O00O0OOOO000O0O0O )#line:155
|
||||
OOO000O0000O0OO0O =None #line:156
|
||||
if hasattr (OO00OO0OO00OOO0O0 ,"write"):#line:157
|
||||
OOO000O0000O0OO0O =OO00OO0OO00OOO0O0 .write #line:158
|
||||
OO0OOOO00OO0OO000 .__OOOO00OOO0O00O0O0 ['expired']=time .time ()-(OO00OO0OO00OOO0O0 .save_date *86400 )#line:159
|
||||
O00O0OOOO000O0O0O ['id']=OO00OO0OO00OOO0O0 .id #line:160
|
||||
OO0OOOO00OO0OO000 .io_stats (O00O0OOOO000O0O0O ,OOO000O0000O0OO0O )#line:161
|
||||
OO0OOOO00OO0OO000 .net_stats (O00O0OOOO000O0O0O ,OOOOOOOOO0OO0O00O ,OOO000O0000O0OO0O )#line:162
|
||||
OO0OOOO00OO0OO000 .cpu_stats (O00O0OOOO000O0O0O ,OOO000O0000O0OO0O )#line:163
|
||||
OO0OOOO00OO0OO000 .mem_stats (O00O0OOOO000O0O0O ,OOO000O0000O0OO0O )#line:164
|
||||
public .cache_set ('stats',O00O0OOOO000O0O0O )#line:165
|
||||
OO0OOOO00OO0OO000 .__OOOO00OOO0O00O0O0 ['detail']=O00O0OOOO000O0O0O #line:166
|
||||
return public .returnMsg (True ,OO0OOOO00OO0OO000 .__OOOO00OOO0O00O0O0 )#line:167
|
||||
def write_cpu (O0OOO000OOOO00OO0 ,OO0O0O0OO0OOO0000 ):#line:169
|
||||
OOOO0OO0OOOO00O00 ={"time":time .time (),"cpu_usage":OO0O0O0OO0OOO0000 ['cpu_usage'],"online_cpus":OO0O0O0OO0OOO0000 ['online_cpus'],"container_id":OO0O0O0OO0OOO0000 ['container_id']}#line:175
|
||||
dp .sql ("cpu_stats").where ("time<?",(O0OOO000OOOO00OO0 .__OOOO00OOO0O00O0O0 ['expired'],)).delete ()#line:176
|
||||
dp .sql ("cpu_stats").insert (OOOO0OO0OOOO00O00 )#line:177
|
||||
def write_io (OOOO00O0O00OO0OO0 ,OOOOO000OOOOO00O0 ):#line:179
|
||||
O000OO0O000OOOOOO ={"time":time .time (),"write_total":OOOOO000OOOOO00O0 ['write_total'],"read_total":OOOOO000OOOOO00O0 ['read_total'],"container_id":OOOOO000OOOOO00O0 ['container_id']}#line:185
|
||||
dp .sql ("io_stats").where ("time<?",(OOOO00O0O00OO0OO0 .__OOOO00OOO0O00O0O0 ['expired'],)).delete ()#line:186
|
||||
dp .sql ("io_stats").insert (O000OO0O000OOOOOO )#line:187
|
||||
def write_net (O0000000OO0O00OO0 ,O0O0O00O0OO0OO0O0 ):#line:189
|
||||
O00O00OO0OO0OOOOO ={"time":time .time (),"tx_total":O0O0O00O0OO0OO0O0 ['tx_total'],"rx_total":O0O0O00O0OO0OO0O0 ['rx_total'],"tx":O0O0O00O0OO0OO0O0 ['tx'],"rx":O0O0O00O0OO0OO0O0 ['rx'],"container_id":O0O0O00O0OO0OO0O0 ['container_id']}#line:197
|
||||
dp .sql ("net_stats").where ("time<?",(O0000000OO0O00OO0 .__OOOO00OOO0O00O0O0 ['expired'],)).delete ()#line:198
|
||||
dp .sql ("net_stats").insert (O00O00OO0OO0OOOOO )#line:199
|
||||
def write_mem (OO0O00O0O000O00OO ,O0000OO0O0OOO00OO ):#line:201
|
||||
O00OOOOOOO000O00O ={"time":time .time (),"mem_limit":O0000OO0O0OOO00OO ['limit'],"cache":O0000OO0O0OOO00OO ['cache'],"usage":O0000OO0O0OOO00OO ['usage'],"usage_total":O0000OO0O0OOO00OO ['usage_total'],"container_id":O0000OO0O0OOO00OO ['container_id']}#line:209
|
||||
dp .sql ("mem_stats").where ("time<?",(OO0O00O0O000O00OO .__OOOO00OOO0O00O0O0 ['expired'],)).delete ()#line:210
|
||||
dp .sql ("mem_stats").insert (O00OOOOOOO000O00O )#line:211
|
||||
def get_container_count (O0OO00O0OOO0O0000 ,OO0OOOOOO0OO0O0OO ):#line:214
|
||||
O0O00OO0O0OOOO000 =OO0OOOOOO0OO0O0OO .url #line:215
|
||||
return len (O0OO00O0OOO0O0000 .docker_client (O0O00OO0O0OOOO000 ).containers .list ())#line:216
|
||||
73
class/projectModel/bt_docker/dk_volume.py
Normal file
73
class/projectModel/bt_docker/dk_volume.py
Normal file
@@ -0,0 +1,73 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# YakPanel
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# Docker模型
|
||||
#------------------------------
|
||||
import public
|
||||
import projectModel.bt_docker.dk_public as dp
|
||||
import docker.errors
|
||||
|
||||
class main :#line:1
|
||||
__O0O0O00O00OOO00O0 =None #line:3
|
||||
def docker_client (OO0000OOOO0O00000 ,O00000O0O00OO0O0O ):#line:5
|
||||
import projectModel .bt_docker .dk_public as dp #line:6
|
||||
return dp .docker_client (O00000O0O00OO0O0O )#line:7
|
||||
def get_volume_container_name (O0O000O0OOO00O0O0 ,O0O00OOOOO0O0O00O ):#line:10
|
||||
OO000OO00OOOOOOO0 =O0O000O0OOO00O0O0 .docker_client (O0O000O0OOO00O0O0 .__O0O0O00O00OOO00O0 ).containers #line:11
|
||||
O0O0OOOO00000OO0O =OO000OO00OOOOOOO0 .list (all =True )#line:12
|
||||
O0000O00OOOO00O00 =[O000OO00OOOO00O0O .attrs for O000OO00OOOO00O0O in O0O0OOOO00000OO0O ]#line:14
|
||||
for O00OOO00000OO0OOO in O0000O00OOOO00O00 :#line:15
|
||||
if not O00OOO00000OO0OOO ['Mounts']:#line:16
|
||||
continue #line:17
|
||||
for O0O00O0O0OOO000OO in O00OOO00000OO0OOO ['Mounts']:#line:18
|
||||
if "Name"not in O0O00O0O0OOO000OO :#line:19
|
||||
continue #line:20
|
||||
if O0O00OOOOO0O0O00O ['Name']==O0O00O0O0OOO000OO ['Name']:#line:21
|
||||
O0O00OOOOO0O0O00O ['container']=O00OOO00000OO0OOO ['Name'].replace ("/","")#line:22
|
||||
if 'container'not in O0O00OOOOO0O0O00O :#line:23
|
||||
O0O00OOOOO0O0O00O ['container']=''#line:24
|
||||
return O0O00OOOOO0O0O00O #line:25
|
||||
def get_volume_list (O0O0OOO0OO000000O ,OO0OO0O0OOOO0OO0O ):#line:27
|
||||
""#line:31
|
||||
import projectModel .bt_docker .dk_setup as ds #line:32
|
||||
O0O0OOO0OO000000O .__O0O0O00O00OOO00O0 =OO0OO0O0OOOO0OO0O .url #line:33
|
||||
O0O0O0OOO0OOO0O00 =O0O0OOO0OO000000O .docker_client (OO0OO0O0OOOO0OO0O .url )#line:34
|
||||
O0O000O0OOOOOO00O =ds .main ()#line:35
|
||||
OO0OO00000OOOOOO0 =O0O000O0OOOOOO00O .check_docker_program ()#line:36
|
||||
OOOOO0OOOO000OOOO =O0O000O0OOOOOO00O .get_service_status ()#line:37
|
||||
if not O0O0O0OOO0OOO0O00 :#line:38
|
||||
O000O0000OOO000OO ={"volume":[],"installed":OO0OO00000OOOOOO0 ,"service_status":OOOOO0OOOO000OOOO }#line:43
|
||||
return public .returnMsg (True ,O000O0000OOO000OO )#line:44
|
||||
OO00O00OOO0O000O0 =O0O0O0OOO0OOO0O00 .volumes #line:45
|
||||
O000O0000OOO000OO ={"volume":O0O0OOO0OO000000O .get_volume_attr (OO00O00OOO0O000O0 ),"installed":OO0OO00000OOOOOO0 ,"service_status":OOOOO0OOOO000OOOO }#line:51
|
||||
return public .returnMsg (True ,O000O0000OOO000OO )#line:52
|
||||
def get_volume_attr (O00O000OO00000O00 ,O0O0OO0OO0OO0O0OO ):#line:54
|
||||
OOO00O0O0000O0O0O =O0O0OO0OO0OO0O0OO .list ()#line:55
|
||||
O00O00OOOOO00O000 =list ()#line:56
|
||||
for OO0OOOOOOOOO0OO00 in OOO00O0O0000O0O0O :#line:57
|
||||
OO0OOOOOOOOO0OO00 =O00O000OO00000O00 .get_volume_container_name (OO0OOOOOOOOO0OO00 .attrs )#line:58
|
||||
O00O00OOOOO00O000 .append (OO0OOOOOOOOO0OO00 )#line:59
|
||||
return O00O00OOOOO00O000 #line:60
|
||||
def add (O000O0OOOO0O0OOOO ,O0OO00O0O0OO0O0OO ):#line:62
|
||||
""#line:70
|
||||
O000O0OOOO0O0OOOO .docker_client (O0OO00O0O0OO0O0OO .url ).volumes .create (name =O0OO00O0O0OO0O0OO .name ,driver =O0OO00O0O0OO0O0OO .driver ,driver_opts =O0OO00O0O0OO0O0OO .driver_opts if O0OO00O0O0OO0O0OO .driver_opts else None ,labels =dp .set_kv (O0OO00O0O0OO0O0OO .labels ))#line:76
|
||||
dp .write_log ("Adding storage volume [[]] succeeded!".format (O0OO00O0O0OO0O0OO .name ))#line:77
|
||||
return public .returnMsg (True ,"Added successfully!")#line:78
|
||||
def remove (O0OOO000000OO0OOO ,O0OO00OO0OOO00000 ):#line:80
|
||||
""#line:86
|
||||
try :#line:87
|
||||
O0000O0OO000O0O0O =O0OOO000000OO0OOO .docker_client (O0OO00OO0OOO00000 .url ).volumes .get (O0OO00OO0OOO00000 .name )#line:88
|
||||
O0000O0OO000O0O0O .remove ()#line:89
|
||||
dp .write_log ("Delete storage volume [[]] successful!".format (O0OO00OO0OOO00000 .name ))#line:90
|
||||
return public .returnMsg (True ,"Successfully deleted")#line:91
|
||||
except docker .errors .APIError as OO00OO0O000O0O0O0 :#line:92
|
||||
if "volume is in use"in str (OO00OO0O000O0O0O0 ):#line:93
|
||||
return public .returnMsg (False ,"Storage volume is in use and cannot be deleted!")#line:94
|
||||
return public .returnMsg (False ,"Failed to delete! {}".format (OO00OO0O000O0O0O0 ))#line:95
|
||||
58
class/projectModel/dockerModel.py
Normal file
58
class/projectModel/dockerModel.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2017 YakPanel(www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: zouhw <zhw@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# 项目管理控制器
|
||||
# ------------------------------
|
||||
import os ,public ,json ,re ,time #line:13
|
||||
class main :#line:15
|
||||
def __init__ (O00000000O0OO000O ):#line:17
|
||||
pass #line:18
|
||||
def model (O0O0OOO0OO0OO00OO ,OO0O0O000O00O00O0 ):#line:20
|
||||
""#line:29
|
||||
import panelPlugin #line:30
|
||||
OO00OO0OOOO0OO0O0 =public .to_dict_obj ({})#line:31
|
||||
OO00OO0OOOO0OO0O0 .focre =1 #line:32
|
||||
O0OO000000O0000O0 =panelPlugin .panelPlugin ().get_soft_list (OO00OO0OOOO0OO0O0 )#line:33
|
||||
__OO000O0000OO000OO =int (O0OO000000O0000O0 ['ltd'])>1 #line:34
|
||||
try :#line:40
|
||||
OO0O0O000O00O00O0 .def_name =OO0O0O000O00O00O0 .dk_def_name #line:41
|
||||
OO0O0O000O00O00O0 .mod_name =OO0O0O000O00O00O0 .dk_model_name #line:42
|
||||
if OO0O0O000O00O00O0 ['mod_name']in ['base']:return public .return_status_code (1000 ,'Wrong call!')#line:43
|
||||
public .exists_args ('def_name,mod_name',OO0O0O000O00O00O0 )#line:44
|
||||
if OO0O0O000O00O00O0 ['def_name'].find ('__')!=-1 :return public .return_status_code (1000 ,'The called method name cannot contain the "__" characterrong call!')#line:45
|
||||
if not re .match (r"^\w+$",OO0O0O000O00O00O0 ['mod_name']):return public .return_status_code (1000 ,r'The called module name cannot contain characters other than \w')#line:46
|
||||
if not re .match (r"^\w+$",OO0O0O000O00O00O0 ['def_name']):return public .return_status_code (1000 ,r'The called module name cannot contain characters other than \w')#line:47
|
||||
except :#line:48
|
||||
return public .get_error_object ()#line:49
|
||||
O0OOO0O0O00O00O0O ="dk_{}".format (OO0O0O000O00O00O0 ['mod_name'].strip ())#line:51
|
||||
OO00OO0OOOO0OOOOO =OO0O0O000O00O00O0 ['def_name'].strip ()#line:52
|
||||
OO00OO0O0OOOOO000 ="{}/projectModel/bt_docker/{}.py".format (public .get_class_path (),O0OOO0O0O00O00O0O )#line:55
|
||||
if not os .path .exists (OO00OO0O0OOOOO000 ):#line:56
|
||||
return public .return_status_code (1003 ,O0OOO0O0O00O00O0O )#line:57
|
||||
OO00O00OOOOOO0000 =public .get_script_object (OO00OO0O0OOOOO000 )#line:59
|
||||
if not OO00O00OOOOOO0000 :return public .return_status_code (1000 ,'{} model not found'.format (O0OOO0O0O00O00O0O ))#line:60
|
||||
OOO0O000O0OOOOO0O =getattr (OO00O00OOOOOO0000 .main (),OO00OO0OOOO0OOOOO ,None )#line:61
|
||||
if not OOO0O000O0OOOOO0O :return public .return_status_code (1000 ,'{} method not found in {} model'.format (O0OOO0O0O00O00O0O ,OO00OO0OOOO0OOOOO ))#line:62
|
||||
O00O0O00O000O0000 ='{}_{}_LAST'.format (O0OOO0O0O00O00O0O .upper (),OO00OO0OOOO0OOOOO .upper ())#line:76
|
||||
O0OO0OOOOO00OOOO0 =public .exec_hook (O00O0O00O000O0000 ,OO0O0O000O00O00O0 )#line:77
|
||||
if isinstance (O0OO0OOOOO00OOOO0 ,public .dict_obj ):#line:78
|
||||
OOO0OOOOOOO000O0O =O0OO0OOOOO00OOOO0 #line:79
|
||||
elif isinstance (O0OO0OOOOO00OOOO0 ,dict ):#line:80
|
||||
return O0OO0OOOOO00OOOO0 #line:81
|
||||
elif isinstance (O0OO0OOOOO00OOOO0 ,bool ):#line:82
|
||||
if not O0OO0OOOOO00OOOO0 :#line:83
|
||||
return public .return_data (False ,{},error_msg ='Pre-HOOK interrupt operation')#line:84
|
||||
OO000OOOO000OOO0O =OOO0O000O0OOOOO0O (OO0O0O000O00O00O0 )#line:87
|
||||
O00O0O00O000O0000 ='{}_{}_END'.format (O0OOO0O0O00O00O0O .upper (),OO00OO0OOOO0OOOOO .upper ())#line:90
|
||||
O0O000OO0O00O0OOO =public .to_dict_obj ({'args':OO0O0O000O00O00O0 ,'result':OO000OOOO000OOO0O })#line:94
|
||||
O0OO0OOOOO00OOOO0 =public .exec_hook (O00O0O00O000O0000 ,O0O000OO0O00O0OOO )#line:95
|
||||
if isinstance (O0OO0OOOOO00OOOO0 ,dict ):#line:96
|
||||
OO000OOOO000OOO0O =O0OO0OOOOO00OOOO0 ['result']#line:97
|
||||
return OO000OOOO000OOO0O #line:98
|
||||
1834
class/projectModel/nodejsModel.py
Normal file
1834
class/projectModel/nodejsModel.py
Normal file
File diff suppressed because it is too large
Load Diff
304
class/projectModel/quotaModel.py
Normal file
304
class/projectModel/quotaModel.py
Normal file
@@ -0,0 +1,304 @@
|
||||
QRASP55VO/1DQ98p1csw9A==
|
||||
I8MGJUwtjfcKc5w4E0SmjHtl5KRuv0WI7NyW3SlEwCrZmcmaREiC99KS4CzwW5Su330khbLdQaeuAWr4x/NqQCTep2zIARzdXiKXPh1Fe+M=
|
||||
dBZyCsfrbwqvA0sbdGrIGg==
|
||||
I8MGJUwtjfcKc5w4E0SmjHtl5KRuv0WI7NyW3SlEwCrZmcmaREiC99KS4CzwW5Su330khbLdQaeuAWr4x/NqQCTep2zIARzdXiKXPh1Fe+M=
|
||||
n+0ptngHIPIjFuMNQ53bfoMbif5SSuhU+ED0z8LQ0uRP+8tAmQ/sx0zSKtQtV+DZAsSdFCQjtILVBd7FvDmtwc6THtaa0pvFowRX+Q+yEWI=
|
||||
I8MGJUwtjfcKc5w4E0SmjHtl5KRuv0WI7NyW3SlEwCrZmcmaREiC99KS4CzwW5Su330khbLdQaeuAWr4x/NqQCTep2zIARzdXiKXPh1Fe+M=
|
||||
PEKPgJeDDCLnL9UcS39EYQ0oxS0YHncLtyklh46m5EBkNzGCoSotSCFeO4A9wJZj
|
||||
I8MGJUwtjfcKc5w4E0SmjHtl5KRuv0WI7NyW3SlEwCrZmcmaREiC99KS4CzwW5Su330khbLdQaeuAWr4x/NqQCTep2zIARzdXiKXPh1Fe+M=
|
||||
1u+XjG/2+GSQRv6EzCaWRQ==
|
||||
I8MGJUwtjfcKc5w4E0SmjHwLsErBQ84ek459TV1n0Iir/P4mdpfwDI34s6+8CBN0
|
||||
Z71ucSR75ppLp8TcGPXjF3pMbrAmHfUi73meeu5lk5g=
|
||||
I8MGJUwtjfcKc5w4E0SmjHwLsErBQ84ek459TV1n0Iir/P4mdpfwDI34s6+8CBN0
|
||||
+aWWMzKsJO+aM6tUDo7l22gaN/EfQwY9pVk1jkrGHubq5BMU7tPycF7U4lfA+PnV
|
||||
NyzlU2YOTFNZFPd7RK11YaUw7ZYsBQH6PJOb5a5HaopbJMLTygrp/eIUmAMGN6Od
|
||||
s+bHc/90a3lxFTPvWEu+yQ4hdETfvFmr96jd16JVhvU=
|
||||
a4WDhREt5YBbYTTI0+NOTlxdCabhZWLzl3dzPJCL2ns=
|
||||
H4fJMREGje1RhDKY1u71WkFaRhA2/BXughjkfaZp1RetweG/KCGDvlR75NN9AWxqG7njwjkItebPDjCvvD0ScUXpMVMO8Q7fKdfHqxQvhc0Qo+XFxK2fsZP0OPVxNa30
|
||||
agP6Y0IXgzGYLtZLVcCCZ/0T599xXC8rG/FDWEro2DxfJQNabVUQQfe30RgJll2GWgYLMccciONnZHIUS3Z5qWHn2s7WlDckd+TogFxnamkRlczRvd0o9wecbthheLVo
|
||||
I3U+Q+NUzPWPEuq1msm2jktlvsiPJjAhTZasqurt+e02ugu/S01xy+8g1TfxXg2xBw7u6ZrdCIKv6h8lGzSaB2XtdEhETr84GetEdGL9JNROgGPC7MQ7C+tI+RwFXBStB1/PylFqV2Y5eewvjz6yzB0KARJjv+PUr3VN5C1ldweqNOD6WfVOtgYZlJOd/RKai2gm1Xe/1qHEsrMqBKfzR0r88ShNiOdlXNPN5Q2Kc+9CXEnQQ5w/3oU63fxP1wk3R02xH78wobUwoMnSpGoiOFRVJcXce2/cO/j80Cr9xp/Bq36qcHrFNfxxLOo4NoQeITeD12nvkWwSaNgmpkti9tZqh3rrD0bz/KPjsePqDqaSBQuy8Z+bZn9RP82p+6QscQO8YmQ8zBEN9H1QouaZMs033/PTbriEeQYkdZyPQmaWKMjODPdHjGM3AvUXrex5lNXifEog6jVp9jpCvLXiQWKOl6vCXdhA6N09FEV5+hc23vD2eelgSUOeS/CVWnQn
|
||||
9GxZpCRwMRDPejWR2Vvf+BGs2TNDawMKvXw7wkGFKycwYV+KrGJBLOWE5ZKcXjfZ
|
||||
hqlhGn9T+umTkW8M7AGCyf53pAfC7nEQD4HNVdEJQZLIkmHZl8U57qY1DeVTGYl+nUTy7H49ZrUNzIpKIAr9zZIIyN/9N+wehqLU+wEqAEsnKcNuw/Damkm1gJmpUF/q
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YwSw+qPU1x9H7h5sO7rqpwAq9aEd9/ZDyB7sxwH9WQaDw==
|
||||
TP9zhKzoqP2ZyB/hk4eVp4PgFV6qyVcVcXyg9pUYTH+fe1NKLaf5spkcfWXgRsYJtnS4hcBQTfomcVa3NGK2kw==
|
||||
1V2v8QerKOmubvSxgB4eTBhWeQzn26oNLaz4XtiKd3AdDQBUXiqXQwhmu5WlhFn60xMYWLG5JhZsJWdFpyqQ7A==
|
||||
VmVrGQo2zRokW/ZuO9bN6w0DuXITxu54bKEKszNtCJvIZ0v/QRc2IeaSOENH3l9T90Rkz5x6Un2VmLIOzr8dwA==
|
||||
VmVrGQo2zRokW/ZuO9bN65gGPMYTOZHI9ZQoxsnmP7KLEtSB0GLS5Se79m+TG2t9135KBsD2gO3FZdgx0O9OKmGhezJAz/k4uf64WYthAg9CvHenbGCdg+rCL1QdVGZO
|
||||
VmVrGQo2zRokW/ZuO9bN63uze4Lnmw99IoHHLSLuFlE=
|
||||
VmVrGQo2zRokW/ZuO9bN65gGPMYTOZHI9ZQoxsnmP7JlthBTUL7R5HqxLcjsSXIrwynkyFYqgigXe0guno1SD0MxRQkoinrozEUjd2i76KQ2FdVaMOaG6NgLEeroNbqY
|
||||
xWoGNWjKGPfI4gq8aHoTfCMtL0f3r/mGFy+NqqYlupPtN4LM6Lh/S65ElrzIM2mEFR4wbzAXWHZrnhVLLLAO0g==
|
||||
ut2tmPKYoa0Hz0cuVsUj3tMSGh1ko3z0+MlUSmSyMwhIb1zJinXvIFDxLfLhTecS/1MzMv2RHX+TvRordfgZoA==
|
||||
x2LOCSeSzacmh81ySUhNRyMnvRWiL5oO6Qgq1srO26J5oIdOF2MB2jFyE3kJu+XCO3xi5v0zS0Bck5oPwGmqdg==
|
||||
5nKwQL/1xmQIH02KLn2uCz4YF8qrIN87bFE85HkLc/i7k2M794x2Yq0LfVLigc6ht6OQMPr12G5ehRdntmVxAA==
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
k2Zl28bOLN38qJfNGTaCZ6rMM0mTyJFOy3hLy7u57NY=
|
||||
yfhcGVf2iYc+Ztxqwy9MUIKrmif2LWU+zznzn9UpLXI/s+FPgY2+Hxtx2sMMpbTlTne9WXFpqgJJ6gPk5Wav9w==
|
||||
2wtz2EJ9gcVOn6ULRb1bGIe07hjE+74SGaG0w588uApK/2t5XjeyKC8OdX+1C8HjQ+IfmVBZwTDF0pqgdxhjkQ==
|
||||
VmVrGQo2zRokW/ZuO9bN6/lqCmGJfh2uNEvtBuw26X8w+5enulKar/ZSvLijxaNb/dPvHp6PgHlhD6KLaQ5LS4HdQeIvfc9DPai/jd4+mwsBcN1vPq7nE76tV7UQ7HVwLJrb0xura69ySsodzPM1j9yiS4WA+QFYcOiZSLVhiLqfCr9XBVFfJx44SoYr2facnIdAeqw2baAk/6b5GJTW0bSxIFm9YutewCUa95yzA1QYUb+WlbdF5fohXe/pPENEyoNRGxO1JUaGh6nK9g7YnA==
|
||||
KQe2cpNa8FkcC9SS/NMi8CpV7JOOSbLjDX5EVV0mMeZBU6EHWzQukb4HO6oqSoSn
|
||||
GI0tVzKIRtvBR9LqilOl4U0EMIK6j0pKu8mjRYtcrdG7dZ269LI7frBhzviGc3tyjRVIj7Ajag15BCDZNPPiCQ==
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
KQe2cpNa8FkcC9SS/NMi8G0P9GY6qNLNYbwjnq7t4XZr0KjhChiSWxjHizc34qaJqim4buwZW/fRlFpl/CdD8LcP/CgbTeIlzjwrd8jnfS4=
|
||||
UrJP/jKni+bt3Mjt/LR2/JixjGffYHjGQSIIYHxxdbx6x+W3qD4ODikQky2/dTb0FJxL5jKdPUwgMlZ4WeWfOn9MU6Yj+i91j0dzx6dZUvM=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
JLLU9+nVY1JUMr5gL/q4iFLnR8rZZKgJ3OwXpvTNq3REjghdQYFTNphtNqdZRRnh+6KIUHLhYejxdcDDAMpidcvFYi6gVlk0eEAx627Syho=
|
||||
h5FvPAwG81WNEoTw22EDzkR3HrRLEnwFXkWthPsBXv5FxJO4EU4fGo07ytQwj7zA
|
||||
H4vRWcZMdeGTkaux2duG85KYo6NtqzfaByFi2mNPcgBBHwoC77PGMeI/lbIfKdFGFKByKlbEQzoPmxasTNih9g==
|
||||
2wtz2EJ9gcVOn6ULRb1bGDs+vEyftqMNg0ecms5Hu3Ns+s3h9c+vz6ytuh+HVVQR
|
||||
VmVrGQo2zRokW/ZuO9bN64dGT517FFoHJ0TEwdOhtfnc+CAijAojPGqiIIwkNeAf+ikp4vrFkNt/evEciFGybQ==
|
||||
2wtz2EJ9gcVOn6ULRb1bGNqBvm70dZ7HtlEosE/Nvm4WGWQyuwgvUYRCgxKPD3IXayptF1loB8Wt5TBeELqccO+40wL0pvNylzYrUHw6JBE=
|
||||
VmVrGQo2zRokW/ZuO9bN6x4A95AfXu9BB2SGVN+xyx0QdXN/K+kB5RwpHBtFUdMco7LWTmbDJvRzHVtYD+qEVQ==
|
||||
VmVrGQo2zRokW/ZuO9bN67ezeGNjgojkyMvJrElaSuLp1VoIPcnvjrt1egmDrxsT
|
||||
VmVrGQo2zRokW/ZuO9bN62PFnbgPIhp3A8iSXWSsu5IPoEqGgdDHCzJcdTWYiFwo
|
||||
T09EhIon/1QoA8oqVWmf9YDvrNcJ40cqakka+PgK4WIoJfqJFeo+lh65ATFyUEMyF0Y/+zwyDgyEpxfdJC1T9s7UhkpoJHbxUBQZk4Fz00RqB4T9ckqgL8prAZIi3eST
|
||||
1V2v8QerKOmubvSxgB4eTBy6rynLclEPfDHFwfFdGkrqZYjti0bOFlAKQAZdWvRRBTq4Tw3TkA7zqlFYV3GEGw==
|
||||
VmVrGQo2zRokW/ZuO9bN631PXfqa0WsPxY3cPKsjN++sf3pPhl4PmY0D+iiZJP6K
|
||||
L0eUthVnpkGsmKFAX6d+uKiZA2NxmniTgCRjkzRry5tHeci7yRgrIj81Qcc56UWP
|
||||
4hdB7RJambPsQ0dtPl5R2R2cbNN2oigWOYu+sXAe6NE=
|
||||
Z8EhB+ghYGoKD9XY4aLecICNYZH3MI+WkCe55V3zbmE92inO+KpNM/U7zaoDuAPEuoRzraAIHccyyiUiZq0KCn4SIx0pgaa5qCV5DyiUzg8=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YyVGBH6aNnzPjcK4RvfX4hfYve9n5OSl18xA0qaFTGh/FvjgivZL+gAYkkYN7wuGkE=
|
||||
wgR07xfoapmx6eEnFHXXYpiq7dd9WD1xT5fQ5Vehci+ppnSgw3Uh/4UFjdGtp4C7cvhGp5bS426UifixsSPqnA==
|
||||
+rSqPmR0H16Evq8k1dmRlB4xIbvaYG+O11hO82myw91Ydmx3LodFeccWDl136pyS+nAQAVxikLOkQvSOY9kJQAL4dTpsdxfBRhjl8YNkSe0=
|
||||
YY+NVOVvcj0xKLmCGeWNx2BestjgssDXb997jOzwt9Aq32N7lFRvKaEk5Fl/ha6S
|
||||
tqyC1MJ6XiYh+GD0a1kac5dSvZffsX+eThfLrN6YbFmpi1kaiU7RgZCp0rtM29PiZ3vWLi+ljJuWig8NiQ+4bg==
|
||||
2wtz2EJ9gcVOn6ULRb1bGKZE1Zcf2OrvDEjNWK0WFBUgbaWhDaV89uXGofJoOVRr
|
||||
VmVrGQo2zRokW/ZuO9bN601Odt2qBpBvUnMq3yF58HwhhNM7lVHcWsw71hZ1B8rwe2VgzE/Ygfs/ES/u0phTJg==
|
||||
2wtz2EJ9gcVOn6ULRb1bGE3fWxG5qHjknC55f8ermFzus/o/QnSnnp1lNx6tgemIWgwHLhJMu5mRfNxKVC4tGUagweF1aVyTeSeOgr2pV0E=
|
||||
VmVrGQo2zRokW/ZuO9bN6/3050nTbENCuAHMJP8rPTyx4Hr09t3MP1sylZ2k9TWT1Z/y9kt5XpMdcbz6I/4KRQ==
|
||||
1cV64uRoDtvn/9K8xFmBBX9ZdUkOEyIMST38LHOp7fSKs2ImPRP0uyopElCHPi7HMVolZMF8O0XYdhXxBgTZgEqtCxmaQbs6wC+46PgWeNDCrmBUCzHdmv+1vOWqpreU
|
||||
L0eUthVnpkGsmKFAX6d+uKJozLiMP5XT821uPNJ8RPjEdXEmGnrZWY/p8GPQZsgGWBxCipm0x1x/vOwPH25IOA==
|
||||
9LvBrxm/uKypfgjBGJGYtcBuhWDF5ev4FlLJBPqtxn4=
|
||||
rqA8uevZ84obkmE4+PiALpn7E9+AzYGlYfGJdMimSUSjnNUvkpCHlBESha0byLU3ObnMbt+xpHSu7mkeF29b/TGgdBW9AIpou7zfLCAKfCg=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YwJt+VY8UEHNTi++WTqHhGFcQLxNOcaxrVugGzPuGlKxDpuTXtsBiJx6HKGQdLz9CA=
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWMqK7Soh3XPs5AU7ubhT3vOqORY+HJbq5ao42T+oXB2TxMpFXIxfI/VHCXdH5U/gk8=
|
||||
poFDBYdcnIoac22Rpx3wOFqmecX/dbM0cwOE9JcdOUxhOvVL/xyrkb8pvE3XuSq/AF6vTbgqAOzaclvnzUP78zNBCUHIe9viMRGZD64lExwdRQ37I52ZP24wl2h+HEYnkzG37tN6AaS9pxgDJLGXWA==
|
||||
9Vq3hrd3Q3VGJ7tCv0+KbRjjCn/SrIsjP/N9ZQ31H8s=
|
||||
tqyC1MJ6XiYh+GD0a1kac+C23p8m5Q8Czgkq36h7kR9597Aftw1MKkys8jKCT8dDNm0OhJLEvszQGKdpR/tUZg==
|
||||
1V2v8QerKOmubvSxgB4eTBhWeQzn26oNLaz4XtiKd3DBM6qqjMAtodeg9N3wCm9Gq2yeZjXnN4HfG2ObtojCyuFuu4uJxjeY08uVocnJAWzulcdvmrB+9jE1iVskGH1AwKoc/O1U4u7wqM1+ViPfz4Nc7TcCBSHiHSfnNKMbMSgFTRrNcK1VUSeA+xqt+7Gps9biwxLJJkfYwpud7rzzLTIQYO3dgrSEgNopaKP1wHQ=
|
||||
89eRayX3G8tCX3FDU5IcjcI7XW0AOTd7+zV/GdfWl4M=
|
||||
VmVrGQo2zRokW/ZuO9bN69cX0oe78riTFf2DR0iSouZv8VJVkm4PXJpjAZ8dMu85ue9EvVlif7D0Hfkl6Hg6wA==
|
||||
VmVrGQo2zRokW/ZuO9bN6x2UBXrziXsE1YruI8yEIdpEkt5u9hKDhDnaxZI1tKV/1MiYuJ9V5LAPFKhhY6L1DPpcIKwtbw6ZwveQkIvw4MONL6VbKw7Qe3GYzo57G9ez
|
||||
VmVrGQo2zRokW/ZuO9bN63aR3YocYJrJURmHuOn6NQyL2YNwJCHOOO4dVXSO1OrOu57rWNUOaY/g9Z4DxYYIAw+FuROKSt7S7gbygqMsdJM=
|
||||
VmVrGQo2zRokW/ZuO9bN63aR3YocYJrJURmHuOn6NQxt5CXBImKEYcRbajp+HfFQgcG4V6mNlUB9TfRtQuR8trry1sH16bjkYZEVMTwcB6w=
|
||||
VmVrGQo2zRokW/ZuO9bN66TcS6o6l70yqYAEaLGRTwyJxvl18TfQzpu1GNA+7HjH
|
||||
VmVrGQo2zRokW/ZuO9bN63uze4Lnmw99IoHHLSLuFlE=
|
||||
VmVrGQo2zRokW/ZuO9bN6zhHFvchcMiaUYiV8FEKyco=
|
||||
x2LOCSeSzacmh81ySUhNR9w5+XreI5pXDQTDZ2h9wlRlZm0n1nilVwIkZR412HMxDvSJoPfkBBhn4MVgLI7ors/3tML7Yd+6oLX9YHq7J8c=
|
||||
TP9zhKzoqP2ZyB/hk4eVp5dwJ3AjKE3bduAuqPgvqjLT78U+Dqd5CSCjq+oD1f0ZsvntMFuytKQk/UqvAUPWuxQYcRKHE4yIrWtNgj+/1e4=
|
||||
TP9zhKzoqP2ZyB/hk4eVp5dwJ3AjKE3bduAuqPgvqjJAEyYSNUdFNS6Lh4D94nUUUjoRv+eD3l2E/Q+p9vL5xMs2E2yAFDG+aCuGb5VjBn4=
|
||||
UTxJ4jWO6dHQO8pTjqkurgCMD/1jMHNO7c5IGagQ/I2QGV7PCdztnRenkMZGlh9+0iLnOQuFMDxZCa1M85F7cg==
|
||||
XX9hoBCxjod6pWwbTwYew9PA9JlQNG5VtJfkL0XPTA4=
|
||||
L0eUthVnpkGsmKFAX6d+uOSGjw9k4+ECXaFBolnRCxXrkljYR7gvNUjTs+cnRe7RhvtQwTDG80WvhjGs0l3aVw==
|
||||
GrDu9Oao7I2P1akJgF09eDtLRscASUn24HyLWqaEGOoLFd3Pyl1FDaBsa3nmHXJlV6TKQFpWc3mjwlMasU2QuQ==
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWMqK7Soh3XPs5AU7ubhT3vOqORY+HJbq5ao42T+oXB2T+dPZSHoCsu8Rvh//+BFVlqkbhy5clkrm5xd5xWnatOtX/i00VnO9Du8rLpc5vQP+Q==
|
||||
KQe2cpNa8FkcC9SS/NMi8BFvFUJwV+XI/wdURlfBJWAKHDHHyrOU8iCWTLbvkh9K
|
||||
rqA8uevZ84obkmE4+PiALkqLDY5CT7nUo6WhuYTmudfvPnqJdzDNw7liPPnKRWgCH5aS6+1HbVYGvtufo0BSXKqCmMResFIg8Yd1Urarz6E=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YxTcmv/VfxPFlecQ2Xnotqt2IE52L3gC7dCe4SN49+Z4J0rlz5DNFH0zxI1SMhseJ0=
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWNJQB7DVYymMOWmjTgS4eEyfy+l4kioIRjPlfjna0D49HQWKrqNczuGOV2UnBCSpJk=
|
||||
npCRXd+WLSmlk7JiNtxtm9gbYh/Jik1FIDXG9IEelYlUIDsISM+xNL1kwJmj6EVRBZZmSfp4awYJxDtGhLbmSnyPSsssdTNdjVh8miFF4Jn/qor6xUfnuQIA6ZtKmpvNSOx1PBvgevr8PiuUrmOT+w==
|
||||
6r4ECPT4o7OwHqIcEmFYzlEbZOlulJHLZOuh0/zLs3M=
|
||||
XmWcjbejqXjijvSDMMApGon2xDjBspqtUFw+zce5TQt7ub7089lB2nVxtLvJitZEjjV+Ih920BeA+wbO6kaybA==
|
||||
8qTxQznEcsQMgFW26Dqik8Cp05AEJsEUSbVdG+IW7IfjrtNpbPkvFbMSrg7fTklWMTS1MlUC5TsFldxvdJejTw==
|
||||
89eRayX3G8tCX3FDU5IcjYVpWBUTJe+6dnMemLr9pO4=
|
||||
VmVrGQo2zRokW/ZuO9bN6w6POkpptsbLbDcwAs1qGzyVhhDiOEGExsweZmFRMA6uit7+z8HqafOBm+f1YAnPFg==
|
||||
VmVrGQo2zRokW/ZuO9bN63pkTmxnYm4QxVHRndiusm21eM9HuqziUJfSxSPrf2PAsXwHDxb8ftSlHSZHnsh24GzGc87Dpn2aHIxSb/ojqvUGBW4iJF9d9xK+17b+BpD5Rw+OA6q5DJ7d0o4S/u9IHjFW8HcRAUi/mlM43BsUCJh/jk3jWn71snZbWPixdQAZzjNUireEtL4ye5p5yYA8qA==
|
||||
VmVrGQo2zRokW/ZuO9bN6xatn4pQf6Qylq3DHGXCyT1/gtrxi1hEFizOSLgOoO67H2dMVxci0va3+/BS4a24dQs62DYcvihjvbPqFll4EGU=
|
||||
VmVrGQo2zRokW/ZuO9bN65da9+cSQosYOCAUllk+pAhHrZNpey+rOYfxZixSyiq9e/vKx2xioCH8T35uXU2iNeWRXpdbAL8h4Lkvzght0U/Ts2rWOX49CLOXyoRKCpwcy8TuX5rPw+VOr42ds1YAPLFlCCg21RSbk7iu+fTC50sk182IVPHmk1sBhgAs9M+bs1klsfK7JJlGrew/cX8A5sVVCSyoYIFcZI1fqs8NZdj8zjoyXLLEDzm6KRkc5qrvSI29znlAPdb0TUzeex0G1Q==
|
||||
VmVrGQo2zRokW/ZuO9bN65mTvxewxktldzaTIh0ruseAf79XDFvSH+mS/WNQRDu58Jt2SHiNf3FiIIVL9XD6qksS8Pi50Znk2FgPbjr91GE=
|
||||
VmVrGQo2zRokW/ZuO9bN67BmtbRZu7DbWxJyGfNqdp2DE5GklxTMrqrBNoUflNgJ
|
||||
sobCGpmMf4/g7+HpPqBjC6JAoG0FhLZpTt8WF4LoCdc=
|
||||
VmVrGQo2zRokW/ZuO9bN6ycgigIJ0vi/BKT5iDenSw2GswKcw3nZbhDFVP46d9mwIKxz8tsOD+PKOJ6VxbkS+Doa2QcmIKejv2R92AsreFRo1/svGGmZidNFI7nhWcXh
|
||||
VmVrGQo2zRokW/ZuO9bN6+wwJYTJogYbw0PvRmy4lbbxRYV2gypJbeoLmseomGGpvhP1RsTU2N4c3EIRExz7t0+QX7ho+8KK9sCVUVaQujq9zlh3iv0vxDOxrHxVoWL0vPQy6OANUn3YB+xIhGV3YCx+4Xg4wSM30SDGMDNrxRAq7ROxx1v4Nz9VcDQJnf3l
|
||||
VmVrGQo2zRokW/ZuO9bN68W7kg6GMlDfsyj9oqABfICnFRJY4e3Ft7u0FDEeTLb+Tttpv2vgL2k8tL9C6IQypvRiZXCeHsld0iOwrv5oWUk=
|
||||
XmWcjbejqXjijvSDMMApGqg66JQONXEM/znZP+hhHbvJqwnVLtBpSTFW1C8zjERP
|
||||
f9qliXFiuzgVqdx2xlu28laTsVt0v0AcLDLGFGh4ei4=
|
||||
L0eUthVnpkGsmKFAX6d+uOSGjw9k4+ECXaFBolnRCxVXWqXRfRFrlYkhQXdVympE
|
||||
GrDu9Oao7I2P1akJgF09eIPmKz1Z36SfVzbX5EtIVBSJLXuLhRL9bU8hNSIy2ELM7gHJn+xHvxDr0YymbaxYQw==
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWNJQB7DVYymMOWmjTgS4eEyfy+l4kioIRjPlfjna0D49BiYt9QMwyQ4CP42XHTRd2Eae4u3klBtdxzhjxB2tp/fpTXxrSMhqObBE8An2UfNyw==
|
||||
KQe2cpNa8FkcC9SS/NMi8I+ywyBJxxH3fLZbImuOz741MPpebUEOYQ++4urBwfNp
|
||||
v88P/mqO0QCsEtt5FQxQSW16A/YQqwPQpq1pkQgukNC1qdmOmTbKBeiUamM5fkCyU04u6JgeNbqszxMDnR3gWGQltPPE/JiBntG4yiEJOhFE81/yTcpkQzySU1/dU0WkEn1B6J44c2f3ZUeAWZFpMwGnZPjHe4mEty4JAddSTnY=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
4ILYwbt7Vw8dM6uHbkq0vJKFyJOT6EmZCVi5TPscIMcKGdQWeHEhTG56vR6HfHecSYcaTVmYfDlfVruxO4vUILrx4YEZmPUd2JfQRcEJJDSvMDclu/6DXDm3D0QaCRqiqvrLHQOib2Vy31zzzYp3RQ4H8P1U8KU0rqQvuCGHL2xnlpGCfIwSNh8v/VjP8cnigUeJ+QAptPmy2DVB/2BwNPs8k2ztWHWvl9bc+7p1e7Q=
|
||||
4IH4b6ywJwYs95/tFiL8lfnVM8cGC/TcQN6wOHKJkru7qKTJqyg+NRdMZZjqWBn3szh6PMq7v8cN3fvQg3xbZuKkD7c/LeXguV4QIOtOzQmInXNic0zqAbqxWrq8yun8i/kQI6c1s/Em6ebGCLvt3rsKACzVCUV/nEuuE364wWwIqGjKqWfzxiUAA73uNvIn
|
||||
4ILYwbt7Vw8dM6uHbkq0vJKFyJOT6EmZCVi5TPscIMcKGdQWeHEhTG56vR6HfHec6/zuyKD4TNiS7umIUQ1eh4mx53BbRpEGDorZQsRxUIdr/Yovh7zG9leoCSODHOex0/be1Sr+cfB5VTJKpjqus0DNc2HZNsgg0ccmxlW6HR6l5lCNTGQD1izZ3oo6Vc3Zvd0NHBGxCrhCEGjroOZL/qmPNTCSc79RhJ/im8x06v42AlgXJtJmMDVKBFY2Ki9kxzkecSlRQld/40PT4PjR5E3/NtH1pOL/to5r7Lfk+/hRui6SIs2FvUkBA6/kIiO4UP5/F0C8bD8DS+HXSEi1JuUaz9t3t6e44P8Q70xu+QOk840HWTXQU9mxACc5PsyDVQ4GOY0Ph0hF72l/O9pPph7Da737jtPgBihJKejdB9cyNG1scb2M0BPnYqR55Hpp
|
||||
4IH4b6ywJwYs95/tFiL8lfnVM8cGC/TcQN6wOHKJkru7qKTJqyg+NRdMZZjqWBn3szh6PMq7v8cN3fvQg3xbZuKkD7c/LeXguV4QIOtOzQmInXNic0zqAbqxWrq8yun8i/kQI6c1s/Em6ebGCLvt3rsKACzVCUV/nEuuE364wWwIqGjKqWfzxiUAA73uNvIn
|
||||
GCWEveFNOjCMyiiJnvM3cj/vlLOzJEJeXu4Wc4MzTT9m/lr3kKqDifw8VnjgCbmzEVvoSNnOlUy5clRfnyQg1A==
|
||||
guSZID0bFQuDFoWO2uxAJsjFYYfXNGsMOQ7vVBnR2Zc=
|
||||
Z8EhB+ghYGoKD9XY4aLecBk1+N/K2p7q6loOj5hO/AY/OY2IChkLDqVzJEzXKrKk5Dhqc8kgf7n8kn3bYhf6mSyxjI41IXmkSnhG277VRrK9M6jwUqP0hzg+3dxRvJy/5bLZrUrlKLLAqdOB1DfhD8hInusaFJKOPu0wf70s1wc=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
tf1Oq1wYbINEkyucXtee1cMgJMhHf1FsUsP2LRuuwug1o39iAStOUDwI0RHQuoo1DY6kPK9KpPHWiGmnoKUpnaFv5CqtlCnc9iB52wcO11EZ+gBlPecinoTKWp2vNyQXL+jk+xFCOP33oQlYIz0BugeM/Xs8WmaxUp+YAPU/27ZVp5rbBob67xkA4H0ahEQtvyWXuaWjvb6vC+TD1+mEEZfT4zwsKh1vwbvDluhn5ng=
|
||||
wyvncB/3/67oBT3vhbMVkleD3cwd9I6ljdxbr1LJWaBalpGbxaXxP/vvYmQVlTq6AXqr+pB5OJA9v+pwNTkRIUjhIPP3l7NehRhk/YXgDF5I6D1WciLFei3jd03xok7qhRg/Cr5NRwF3IWBai3fmz9CCYlyMGnypU8zhPd57O3J+PYMqQcD4Zcup/TfAGEaN0P5evWJFcQLIOV9zlKJ7QQ==
|
||||
tf1Oq1wYbINEkyucXtee1cMgJMhHf1FsUsP2LRuuwug1o39iAStOUDwI0RHQuoo11dIkX7kqHzlkFxHSyD6tnXs+xhWWWFAgjgE6iZVyEvVxS3hDQ1kZ7mZO69wsx7qXMiK++axVuM7kDei6Uc8fdG2Ij3V95ndg3NGhF5c8Ve+M43nLzx5EEadj3AIL988up2jz6IXskD13juE3HHLxstJO7++UKrO3Fph0H0YgADU=
|
||||
wyvncB/3/67oBT3vhbMVkleD3cwd9I6ljdxbr1LJWaBalpGbxaXxP/vvYmQVlTq6AXqr+pB5OJA9v+pwNTkRIUjhIPP3l7NehRhk/YXgDF5I6D1WciLFei3jd03xok7qhRg/Cr5NRwF3IWBai3fmz9CCYlyMGnypU8zhPd57O3J+PYMqQcD4Zcup/TfAGEaN0P5evWJFcQLIOV9zlKJ7QQ==
|
||||
BsAbgDLrhQj2uYn3yuDnJfTmJeo1JkS+iXr7NiMr2ZGVgoDFcakJ59CcFxnHHC81E4rjC26F25zO4kie0jx4Nw==
|
||||
guSZID0bFQuDFoWO2uxAJsjFYYfXNGsMOQ7vVBnR2Zc=
|
||||
QWxBDaw3VAaL036sX4hCHMARERUPqvMRF5uWXT0klt4M8uDrT3wrTUNGrzlsT3SHynX/h4n6qICxWvRyD6/zjg==
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
CjeKMqexO85OxFkNTLsfVe7SITCOKaZp1LGMwqVNe4A=
|
||||
R65WfMhum3uW9cFR5COFLNNgF+xCIveKPUqFxBGX9W8=
|
||||
wbI88h5UWpmLfMPZm1GHGsVMKwcuDJu56WFkvk/fR2TtwNrgHZQRoxBog1rgNcsJMOWUeXIf2/8hfo8KTaG/XQ==
|
||||
JGZY1C2+nS9wZYWgd+gvh082R8I97omw8iSHX8Km7LmoB4CSGmPMOwkUtKpjByEk5vVvPtxTZbu3mWhXtEeW6uJ1VBaEFl9c7YBx5ZTGNMA=
|
||||
SY9CIZHY29IN9pslG93gZg==
|
||||
pVMCrZ7PAAHymZ70WROm/xN7uc37HHCphJNP6wBWNFFkfCrTO3/zWdRXL0JcM+29WG0o7tsUYtBK+YT4qlbtoHBEcSL+oYQx8umm33tHtvxlOnew1yGrW+9tUb/3mIzCXV+bwMsE5oXss2lYpTO3GNQd55Kh2tKBwIfi983jfE5WfGpdHOOq3NWmcvgx1IQ9
|
||||
L0eUthVnpkGsmKFAX6d+uM37yNPNIFu5Sy9mvfTDYR40t895iJsTBk2DH1n3Un8e
|
||||
TTmoxB5HuP9wmwf8x1QYvrn+3uJVMIWBGgMruE5M1BU=
|
||||
QWxBDaw3VAaL036sX4hCHMx8zffAVdfqNc5+di1I5xBdsKxDZKivqDomKrgNbiQV42S8BdMCjk5yRAW6CwZB8g==
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
fnnuZD0QAdxvV2PveMWL8FOZqBJQkO5fkDyErcdv3sHBCTMsJBafZRCNzddg0fI312AFmwseKma+xsssgq5CNQAjmSvAJCGuc0eXbxvMQOdAMf1OlFFfed4k7hRAM3At/KtVPJ5SelXm8whoB/FEOXQ3qFgH/HpWgizR1mjK/e6ou5uOv4f39VcQKtXRn2Jd
|
||||
3eIpXgbBonaoheCPx8AFY6umFI8slLWq/upaa1Uk2jpSVyMvPJ4mcBuZLgraO+q9GQedAucc4xrSwIqyV/B6gCTFpRYHtmfOoqOLaWkwYvc=
|
||||
4/4+Wm3Rsh2mkp+PCxs2s6VV4mJNPEuvR7w91QHZ557aHaU/Cb+THTNE07rfYLXxrdZDRZPikp+SWMJYE4H3Ig==
|
||||
dID/HuTFI39RGoF22OwzKyXop25iN/6Cgmas1ryG/r0=
|
||||
VmVrGQo2zRokW/ZuO9bN6yIQVC/ANBR72Zf+NN0mt0yltbzDkWCCV7TF+F4d/yUWRi3IdQCvPfYZK+rRnnypTQ==
|
||||
VmVrGQo2zRokW/ZuO9bN60bK2UgxkvkWzml09hTN25JfpBLx03bYbZyT1mbcJLoM9IlxgO6bebtiUCLu238r87hHo/BkL3I8dZPhAAdHYzQ=
|
||||
VmVrGQo2zRokW/ZuO9bN69XWNCdW2VwaznplNhiELZFhveDssDscfLsEq3UYW8Iw4usKj8FTxO0dSaukGj8cnv8+vtmaKEgZ0bN/GMY3GQDbfxr0gYg6NdbH2kpceCeziSX72rUP2GIAP/ebCA3AjE8/vyUHOlZUHuT08r4QEqVOFV6VX0kqtotk/D+bdiQoW4FGuVaT65K0qS+w4pQd/A==
|
||||
VmVrGQo2zRokW/ZuO9bN61k54EIrXJ5YDEJYX7KVSMQJb2yB2/tKePc0AJNb7scfmBx3ZMDkULLl85vjDrKPDsRbYCCYbmQ4JM/pYb5gQtg=
|
||||
VmVrGQo2zRokW/ZuO9bN6+4h+8nsMn2hxb5D0Q6u6aGCqIPaFsLj6fC1TahQFgsNH4kuSQ+lduIVprP5UXJaS/58J7CKl19/ZhwZDgV8O6QU8iHj73adX3xjmEJZkf6Qrfvc431ZzHai1xsHjSFJgmjI+xwBn+vfmSyEbXYaPyIavlSyj91iOeD8FqpN4irSOGSrBibcPvxEkbNEBWdfzw==
|
||||
VmVrGQo2zRokW/ZuO9bN68wHZtGYQdFVE6PwKTgvaNtYzBFUcYX3fyY/6M9/dXzj
|
||||
VmVrGQo2zRokW/ZuO9bN60GIVQb1dVeSTDjJFx4iZ8K1YL/MjcMgl0IDPsbhoWcM7yQ9EOiw907XJNWeGVgujqehYoLtC9EudSNuKe99+CWrrATAnvnn66j4nlkv3EcPJUeAgTtZo77f5zqZOUsiGesKkQIGJJ6zd/3K7c2P48s=
|
||||
VmVrGQo2zRokW/ZuO9bN6/o4zScwQoTUi+tr1czRySSTBNwD3hHM9vC0XVvu0iF/uL9dBtNk/w6BB5ctKdmT5CcwaDY3ncMWkTQB13YuBkvaC3/J+X6jTdOr7PDuX2PSynf0+gGLE/QAUz3VFC0aHU1OhnUAoA9NI005K47zs9vF8K4GOfiRNWxWRaEo61bK
|
||||
VmVrGQo2zRokW/ZuO9bN6y0EoUp3iWRH9OmX39lPFAedKJOagVu1hc7h3Pe4GIyhE4KZU3Jx0OYEExfBCrAKqagP9yem43/r6C4T8+tDACodjJey9cFkvf//RgViLJEY
|
||||
VmVrGQo2zRokW/ZuO9bN696Qz5c9i0uv9aeGTx01h1hC3aUrUxbV7GyHYuGQp68o9ge64GJUGHt5FQuweqvNs7qVTiNgWwYE10vLvinIRsMYIM/myPIdDv/AqzuwHVzOOae1yPP1GqFmx4OoiOna/EGkKRt3Z8kNd3k4/rs4wwzo61sa5wcv2NX4XAwqnj1CEvFdWPd/bPz5yy3bIgVjgSZPiSvSqJXgxQGFENnWTi4=
|
||||
VmVrGQo2zRokW/ZuO9bN67tgFk4kAxPV2NXuFIabsssnHcnxv5PUS7w7nqdNDlZmad2xlF197WUG6enWS1ddeO2lu2wARsOMM3olmtoDpSE=
|
||||
VmVrGQo2zRokW/ZuO9bN60bK2UgxkvkWzml09hTN25JfpBLx03bYbZyT1mbcJLoM9IlxgO6bebtiUCLu238r87hHo/BkL3I8dZPhAAdHYzQ=
|
||||
VmVrGQo2zRokW/ZuO9bN68mt+2TzTj2DszDWHbL/Vx+mrPtVnbW+SD1pBk7cc7rsaJwQNo4QU7LoHvOicKqoaUNdoG5e+AzVGaXRW1n1Nqg=
|
||||
VmVrGQo2zRokW/ZuO9bN67wpbXh8GxRtxxUdyv9+tcnQYOPzlH126m/rftVMv5cRl/hQkptryk/t8Gtg8ajJsb8lwpAI2nvgWtGpl8TpQ+K9nHJFRXKol1tZrc9/ipu8kaOocsRDzkPn1olW6CDnbALkALXUpIrfjvDKrygdIdVqX4xoNpvqmFtSkD/wGtSGVW8x0++ZkFMLlzwBleSXIofOOFMqbdm8kP/g/2Q9cnM=
|
||||
VmVrGQo2zRokW/ZuO9bN61k54EIrXJ5YDEJYX7KVSMQJb2yB2/tKePc0AJNb7scfmBx3ZMDkULLl85vjDrKPDsRbYCCYbmQ4JM/pYb5gQtg=
|
||||
VmVrGQo2zRokW/ZuO9bN6+4h+8nsMn2hxb5D0Q6u6aGCqIPaFsLj6fC1TahQFgsNc8McXaMNkcQsuyQNX9sTxBDIVJELewreELhbA7ExKAhYHdGr0vUfJ656qPdz61pEMCuI1svU236YOtcqeeWw9hqHZiYtOwsjiw0R7ymDlNoj5gwm+V1FBszZXgoQ/hN6BxqCiqLFSweS/VzkreCfWAHbQNqrDsEDcEKlGn64ivJUmuj9zyfGuDZOIHE/SGBUK2SlyF9yV95YTadwSATEnw==
|
||||
VmVrGQo2zRokW/ZuO9bN6/AO4eShpSZK4uRSltMUWur6UmoAJ3uYmBh6Hb4u8+QZuLnJtd07ycHQVITOJweo3B01crh9ZOyXk+RD4zH9h3dxaFHiZPGzCPB05djMX/pZ
|
||||
VmVrGQo2zRokW/ZuO9bN6zhHFvchcMiaUYiV8FEKyco=
|
||||
VmVrGQo2zRokW/ZuO9bN6yIQVC/ANBR72Zf+NN0mt0w5vOuC994hsp0d+uCS6/55EZLchuUQTeEJwheE06nZPQ==
|
||||
VmVrGQo2zRokW/ZuO9bN6z1vYAYiDcZJ2goOT3IWOLIPUh30Y1JucFlnMHb1teNZ16yXgRYuOnoJWnC9DJL+4Zj/1ue9Mx4yCXqgEarMjmo=
|
||||
VmVrGQo2zRokW/ZuO9bN69XWNCdW2VwaznplNhiELZEzh9jk6I0q3rmZW4u4dtEB5X/k82/6F0+ZL0tohkmBOkIUMP4Pr0PSa2rrEIkJpyeCRFXjMs6Jo7fo5NVOVuWlM5YByI4VbPYwOI9kC8H+zNIdR0QyalN2tczBM2yXnr+zlXuJh0AhmzcDReqsIiJHe8wIa9fruyQvytkiCOU0rw==
|
||||
VmVrGQo2zRokW/ZuO9bN60CwpxhzHd5Tsu3VuWdEIGbC5Eco8WcHvSLIMGZrC4J8HM7Mhe6VWR6L/Sg/mo+5Ug==
|
||||
VmVrGQo2zRokW/ZuO9bN60+OYD9Lp6v7rDnBJufgyu0dtNrYkL8H7zhFQ+vQrlqhvCE6NtoBH6ioyORLFJjNRF9SGfkFntthQsprIkcvCtCK/JhjIZowEZYnAX2rXG2bsXd3yGimQl5GilD4VC9gNoyJDrUbIX84KmcwTFd8/LRErn07610YcZNUf1UtMXy9vd3qDn0Q/AVxLd1KCmzh4jDf+6iTl3HBqq6d9N7CJeNtaOYmfKxXO3OYOtgspRP3
|
||||
VmVrGQo2zRokW/ZuO9bN66jTdv1hTu+4fFiv1YBwZue7lv6Aufd7luwy7B+0aC0dbzx6VRSrf3fzINUzlq8XMNkGKWBWvxEGkmN/9UAOa6dKPNyUHrHmxW5rH1tExZwQ
|
||||
M0ZySqkmhuHCw6olbCKv99p0Om1sGOCLOPcvWBGiKm4=
|
||||
VmVrGQo2zRokW/ZuO9bN6/IJQworJPCLdiBBDQz9p5RwSTJBcPPTw2MHkE7h2GTjhvnVFr+q/CK5r4h+EYXiyQ==
|
||||
iwvjn39WsWBJqN2zZdgrYJ/brbUvLQT8xFC2K/CMfMpSLWjSyTEJEwqWm0w226ndjFtOnyhoGwu9FfNq6tbV24x74jC3NVVQJ/zXWM50PNKF5ZjzeY6CK05/XMakHiEDBjCNUSVpX7NFuVqFBQoXFQ==
|
||||
dKwZPlLLroeAXoKoRvFRMPkQmp49Bc6BILmWMD0egRbJufQJJVHeUyhmpinBOzpu7lZkSTQPR3sLPWAb1XrOdBks43Ja3veKdkPBsYEtP+4=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
fnnuZD0QAdxvV2PveMWL8GG3YPzBkIz9Ea9idqA0hv7KzY3K3PuUh9EVgCFxsnuQ948EJfpPabGHe6RQ1WLXqx3Sw1oJIpfRNJqpmc8NXbiDy0sb/I/Fx6BFCgQNeSfWkMOO46FZGiOPxWAfogF5t95B5JeJd/sxMl1fwroGSOQGzaf7YZCSCW9ezDLi1u3T
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YxTYMkXt8S0Nah7w8r9TF300puk+OnsqWzfPRMs3Mbi7zOrp3cqhM0qeqORamoAJBM=
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWNGuMooTRErT71B83/M8nD4aRWyyME7sQDlOs9XPKbRnkn/lNp5zeuNE5AF5qUcgYw=
|
||||
XmWcjbejqXjijvSDMMApGpsWw+e7nEJCTIvfvDqrkKXboOR4vzQVwubyAa+M5U2ai7wdT1soKMjQ5oH6v9r1qQ==
|
||||
7iJfWS/hi94/vke2djffqmjBjwDgzRyWSoEw1Q3z3GT4V7Je3CZ1mm5s206h0RWJN8GlLviN43HL/e8mdYfKB8xyWTX906NaD7r9udlkATM=
|
||||
WTPaI3KC72IatMBY2cUf8DhINsfbwu2z6BUbAhOsimUwCOTh2mByfFmolL6LGlAzznx9YHBnysnjX5w3K0Aa4lU42GWBOTkXRGOsJGciABerQH0fIN3Cc0Ha2WQAmXrtVkuiFi7WSacqVGM92Wz0RA==
|
||||
yfhcGVf2iYc+Ztxqwy9MUGl2MlVdixWiPkpdkDIaDTR2fL2bGJ0eG/T3S3mFK3I1yjUKdBI/7/TjB+C0Q1TF7A==
|
||||
2wtz2EJ9gcVOn6ULRb1bGHs/k+FAu74ujznevW9tehQxxh+/BQiuLboLlLsvhekSf7bU2kLTTL5K33sDNiX0trhbG01wTa4j5HspvJM+CjY=
|
||||
VmVrGQo2zRokW/ZuO9bN62zAi72PGE+cjoOBruJcs80PAY9N3iH7ke6TUqsi1sSy8D9ganeo6V2zi4SBqW2bdOnBzTgDx5DTrEDZzIkiR6xafY1QNC1k21Wx2o1UPd5i
|
||||
WTPaI3KC72IatMBY2cUf8GcB7Gs9lcHGWbUjG0C9vSs70Ygjj7wUoEbxnNP2i9zrzgxlxVIkk0U+7ydFZHSoEzXRRuiyI8zt4O/5cZ2lMz2J5pBt8vqrB5dxECjlX6ZE0SioSpP6KutnXcCf1ehJKTCWzRi2xhcBQ0FshyUTLQg=
|
||||
iwvjn39WsWBJqN2zZdgrYIdzLsQ825kgPBf5VIBdj3uoMjS29MAx3RxOuWvlnXiosQ7KPIpTLW0MUcNlsu/ulyBkoOXWnXGiVxFPDjplOPmOZH25r/PenV+QVxeQxMCQfVpOT+W5VTimeAhxNV8PQw==
|
||||
iwvjn39WsWBJqN2zZdgrYJapEN/AKnY2zLbcAIzyrBBU1RXGfgWqmb+6/1Y8honwoq8vQFNWL5QXG2xnJPe0LBPl/ycfTdBL8st+Ep1mgsYzpmdsWR6INN9Bz4yFZESMs7wbMHG0SzC3fg0QgFp086x0icWfwhosFLdQWu1ZDy/D1nu3zd6GRjYEiiID4hWyqMGLVMlVhlgucIyj8rJvGGu4F9qYL8XJEbUPtev2y4Q=
|
||||
j950dDFgNocMT/8FQS6TYJHV9Kyoac68bruP5hOu5qmaOOkbdmWW75ouQPYNKTGSSa2ykeEdUHfzKTkJdx/Ccg==
|
||||
96orka/uERLyRst14azQwifX4NgxGrWxr0Kq7A5Rg2HnATx3FBLn85SCdMGIOm1E0hlma+GxHkgZc93eWmwVjA==
|
||||
bqFhodE9GHP09Cm0jqHUfmkdtpV9kuGe/MGw5ZaaoCp81F/rxUszv1KfXRZWtOlE3la7p6gT6SCyEt8mcZzS2A==
|
||||
q4nc/jwATOMUyfSjLibfEbtbU6LFt5q4ewa9MuGiJMo=
|
||||
jsE17/UlKDH9XrhQJJowi15/y5gn5lH8c7Gqcnf3Esr7fxvcWtKirtM5TT2hHcoLOOiNTfJ5a7izuUZ8eDTQRw==
|
||||
jsE17/UlKDH9XrhQJJowi9yxaM1QuCYxVef9FbIoMZ+eKsxoKPzwQ/wwh+qx24Hi
|
||||
AaCYXSBoNzzxOXBdbJWxCPghQQ+zxvQLtEy2BM3tYqHuDq6yKijsnOS5h2YQlWHI00dhyYcLovqVLkdh0Dy8fMQOez3M0K6+uE8weXP9Ap5DYQqbnNlIhatzkP9KpuAj
|
||||
jceVTICIbdeQFZqTJKGutSjbVQ97l0vRfz6aCyyExd8BAD7ORBXAStcGQntGkH9VeVHgeQxgUAn9i5xQBjtmtg==
|
||||
w07xSMqKvzErqU8Z4gNDycTDkv3aRFmhNSvV3Fxu24BqPo3ptCHykzMf9nG/CGMxQaiucRiWiW3Flz8o49yWP5RB3d68MNFb5mogSyWvDQA=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
fnnuZD0QAdxvV2PveMWL8CSqz+/2LSHUFrClcf5BdQrTv1c0XJfhDdpDKKPo0z0b14+xocsVY8vCZj/69cLwfoiB1FEWbmyYbrlCddxFGEsCX5QCEQvSd95BTrhq1nlZCNY9ga7YYTrfSnw+46RbFP+ovv8K0iZCj+u7EFMHJ/IMXwLlnh3z3jdyNDu7TFNo
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YxDlh4Xxnj94+dsoExgikc543ZsABYd7Ls6YBhmFxb45wha5ZOThRb9RHRh4ve9w0I=
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWO/PpcmZKW2bAAbmrDnw1SCP4uaE0ZYA6R3BnA+nWDqAy1mL3cUFeM8frCNXgKcWp0=
|
||||
ncUn2TP8ZQ4fZMBYk+CUrbejaOCU8cNhJKyCBZWCqq1sY02wl0mD872qKy8RvJgnAbv7KCxyej8W9Q+U+qS+nMiBgdyd4po5Df4qqDwKnLOe/UUDOA1H47u9gqHf8WHl6B1PCla277lpLOkFu7GkR/mj98MnPUXQEt54mzwtDe71lGzby4KJ9Ma/n9OkWQnE
|
||||
A4iM5LeR0j/aNdRd2ACS4ny8WZLXU05tQMpWxiCT9JuuAqjT43MG9lWrq5R0d6qpJwthsL4nn9qcoduCQeoOlw==
|
||||
5REqqEJCYV1z7x5neHLGFDGAviuWIaE/TYt4LSZwDiMXm/53mOKPZnbzemXU4+GZEUcMNcyvWJGIOUQ5RIkIIpC70r0TF2jbHjMwqOoUldc=
|
||||
3DnhOSKd6qzCIAY6ANKkgJYd0P/22B0l1MZyem52ut9bERvo0PX/T68xhBrjCbLsd45eA+op38niJOuRPomiESt7gvsqdzn5rexbsh2MuoA0EOCYOneAtVYTW8225GFO+VCWMzhTlT1SXl7twpHYnQ==
|
||||
R6vHhJwn2j7IZ8/oBXXPlT1VLHYksWD6DKGcKNO8kyDSYJaiXzcsBEJQzsggxUu3
|
||||
yfhcGVf2iYc+Ztxqwy9MUFkJFa9YS88pkqSw34PcNf4lRXLRKL7BLErDKD8oJEUa8Is5OQTKCIYC80QzJUv+ow==
|
||||
2wtz2EJ9gcVOn6ULRb1bGC0c4KGSGGqyU0mFPA7k9/zMuX9TZw/BP1yH6IjAzrb0UW4BCVFU5p42K5W86y/mOUKYixfq2yNN6gEZO27U3aI=
|
||||
VmVrGQo2zRokW/ZuO9bN62alG5rsG3QEZzQ33/QBje3tmhSRMsf9NUXv9udZovEkoqejbYgifjLzt4+lAxk98Q==
|
||||
VmVrGQo2zRokW/ZuO9bN61IpWQW8LyV5vGxMqJtLAMG4GidKSYVzYqLlwKnkYGh3
|
||||
VmVrGQo2zRokW/ZuO9bN66B2cWRLetUcWMU+aw+SZbQ=
|
||||
1cV64uRoDtvn/9K8xFmBBdHLi7PMpkqFYqY7BMozZdA=
|
||||
xWoGNWjKGPfI4gq8aHoTfPboh14laZFSUPEgtjSKUWO/PpcmZKW2bAAbmrDnw1SCP4uaE0ZYA6R3BnA+nWDqA8JKb1hHUBhmO1q9RpqWkO65x899CtNFF6+cegZlLYKatosIHzYd1sSurD0D440aNw==
|
||||
xWoGNWjKGPfI4gq8aHoTfPSftyw23aWBm0SalP6bSZ5uFgWb+TdmXVXjEBOfs4SIpa/FkCphz9Tm5ZgfbL0jqHLzP164gR1SD2C8+k5o8kpAwYIJv84ufmqQyFKhd1DZCis68M8tRgaB6ZXGCaNrCkbBbv1rEFnJ3jwN4L9DvSeA0NBccCpd8oVxmdplQ24eWXMmssJ+SewTSv3wCcPzXui4VvS88RJY8GZHoEgTtE4=
|
||||
UTxJ4jWO6dHQO8pTjqkurrjGYhp2vBYcOlWBI2li3lQTi9a9ylfr2bPqUUBeRL9Lp7KgysTqDJQBOFjwXnAT7A==
|
||||
L0eUthVnpkGsmKFAX6d+uG2V4ODQQv2yL6nL1etYQzYzTVLBKVfwwGviW9wMWGbPvgdbWuIi8fuBLcL8k+2CkM8xJKi/40nY+5NrgF6Um8o=
|
||||
KQe2cpNa8FkcC9SS/NMi8CwZjefuYFdgIVltRQ6d/OEFpkMvPQIEkY8jmyRMDoerHhdkzdV+Z4+gMSYNTzKt6xu+JQBCWWXi1l89v4epCfY=
|
||||
+oS0XSKoqGXJre3Q/1v1BlvSlGCveCkN/Z8cmI+VqTrpmsmHgDb9KkDKC6ZVLS20UIZPb95vU7cgxrlJ21Bc2ar9RFcrYmzQRZ8SjSyJJ84=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
nCZEvlHDeEU72IAmy9hXaHLXXyBaHBxe+RST4mPX/1s=
|
||||
JsM1B8QNr50RvpRbP1YnPuFx5C4ai7Wud51VQmeOJhtTbi2K1dw95XnWrJpGmome1iYmoZa6Oc4Q6EBuZoNV+fX+bUk82IAFMAM49zKO3cBTybz8r0H5oeeZD2PG2vz9YvwAvdCggT5OaK2dzb9qtkyl9EQWU/5TuiTRRLK9wPBcfCiv8BBTrzpbXxUyEJkAlKS7V+HzybJN3Z1X6AT+PKpq6HL9uxam8gsZOZHM2/HTQ3g4puzMy372Km4u6jdZortgp3ZYADH65j98Z05y5Q==
|
||||
fnnuZD0QAdxvV2PveMWL8ChOX9d1DU+esVC4Z+TLQn0LGt4/lA9B1nK95LwQUMwDyBIvMUEQynEPvkKTsUPmBA==
|
||||
tqyC1MJ6XiYh+GD0a1kaczblP9d+7MbugTMefIcU5knRIIUxS/2Wcv7v0aIZ+2c9FzydBTSgZglAaMKN7kCI/+weTX/7RdLptz4gfoDeOVA=
|
||||
2wtz2EJ9gcVOn6ULRb1bGJbVRPKXqKnqQ6mDrr8yTxwFA9NUMvAWHGQpE/FJKpCSlbP5Zg80d4pY2gBPsk7i8ozLuZO1ozYdjzrgJw2U5OUEKIiU1L82Uq2rBkRVdg0FCh+0rlh1SAarvhCyIPm4eg==
|
||||
KQe2cpNa8FkcC9SS/NMi8MCNQ/S9KLk1s7xLXNfFHdSzUR+lpVwNBVZYrPMpnyol
|
||||
oV6EeCQGmWRpCjav7p0xHU9dTzjHsDMOBcmP4S9Cd0Sm/BfUaDvQq6+oeGDChPW7TipeycZUvdKZKFIi70R6ce9xK8Y1ET3qsvaYpUbml/t0t7fn8Z81Ufs3uMSqjXwn
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
6r4ECPT4o7OwHqIcEmFYzuoVsBFhqfPJAaTURpnU6VwScF3eicqvf7HjZ11RI4NP
|
||||
fnnuZD0QAdxvV2PveMWL8AuKdHixQT66Gc00Gg1vJS6+GO0xBdztvdUhCI5Ge5N555Yujja5lRVAwH+nvKDo0g==
|
||||
6r4ECPT4o7OwHqIcEmFYzheDtvHlqty/0KdCgKl0ylz/1KEPPjnNCy+Qa3YCQV4ej0URjhxYyA78RnBZQa+b7w==
|
||||
KkG36smI6M1sDeGTVVD+qSP00dlWGnbBakrMMitnwAHUW1Dpt7HTXNcTRJlaQP8kip102wRtA7YBJRxVLYKDJU8D8qE4aeWEhK4dD0Pl6fVL3wtOaxsjGuUlU3uOMl80q62tcnhnh6ZpLjlBbduGpw==
|
||||
4IH4b6ywJwYs95/tFiL8lY1GyBaN9rJuTeVxWOfmJ6U=
|
||||
2wtz2EJ9gcVOn6ULRb1bGM8IQ2dJE0FhTsv41jhWplnZWgQQDp3w/UtYWI2rgs6eeyYGfdf/TyqbhqX4p71ooQ==
|
||||
VmVrGQo2zRokW/ZuO9bN64SEuusKjyuHabj781H+tb1pbX8IQ6fviKyAJ4bIwo6f1MEOhr9OA2EPLA0laTC+bQ==
|
||||
KQe2cpNa8FkcC9SS/NMi8EFKVhLSE9F1GFAOmsqhoz0nSuR5P8d9BeQpjUGmCKYl
|
||||
PUlTSkp7cRpcs3JwkQy2WnJTeXdbhFjvuSced9pxt6YzgizBmOcyjfpim0HV2MrFzan/z6jOh7I71bA4NdyyuRUOhVQJVxU+8UkcayIiIfY=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
fnnuZD0QAdxvV2PveMWL8JrP786E2VWv6OEVjvqfqal1F0tGEw4g6I+m/uUhNjRha+6HO1sT2iO4abtaK4OE1Vy7eO++Khxe/SuLdIKHyJcUbwrJ8UwpyBO+PNDZ52RrEVi8iM258cNgoOb0YAZQfN7kK2V3iyKgd/GnMPZXMTL4JzhUkcRyggyZfDNgDqT2
|
||||
XmWcjbejqXjijvSDMMApGmQVBFK+3Fu7ffDX8KPyOyo5Q0Ti2ZZ2YMkf71vb/W909tViVHOCaDHTsuIQl/bZlA==
|
||||
HyB13FOAEbSI2KAABytWG1lJdYY/yjhXtGuYXK23U9uctTZthkax3pqCq+KZWhToqgQK7rULc+rIh5RV3cT5QA==
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1Yx/jb+vZHJt3XPEP0sYLVm5vGGxbG9PnkJrq0RBLRyPIHfCkYLqlrQewmKTeUugXsTUbZM0+Bq0egdvyjbtYB3RDS3E8+1Of5ENemfFFdPgZTU4bGrWNIhvEpJReOGDokjH++X8r7oe9AMTBA/AQnDw
|
||||
ut2tmPKYoa0Hz0cuVsUj3qcXVeFDr/mvvHeu4hSOYIh9yLoIX9tq9Y5O/hZBb0tffbu4/T77YQFbF6NFadqzOjISdrhc269PQWx3OJ7ouTW/1PToQZX1+XjOsQbRA6FVDFry8tD5zNbLBVLnSpaRBYyncHoM/p0AK6AxDDXFQ0s=
|
||||
ut2tmPKYoa0Hz0cuVsUj3sGyPnE6nUmywzlUF1eIcgMYiYMpPOa4pahwX32jHUUbAHbImsTgL9Rk7Q5kcJIpqFEt3V081Pokv5C1DXYg8pqGB9PcgYc/0ZKPNh5eLzBu+Y2u8nxkPk+kysiE08xWJ/yoGtaacIJybZbO95Rb254=
|
||||
CTDlCq/Yx3kXyawzsUjqPn4DoEOXY94GKmJFYozlJ3MZVnazWs2aCAAG7WaeGpIc1rom6k73cpvAMPH+Q//OZpGilDx8wm+pDjOdrv5qwBM=
|
||||
qgvPLYf8+6pituXauG2lHnpUgYTRBVrfogZrz8+a40teOzfvu+2n8c/F+VGRE5UBE+95iEDTw4AWhkst55N38A==
|
||||
2wtz2EJ9gcVOn6ULRb1bGC1vdhobTwHQicpopnpHvZykrJyTIAmAai0BhcHk+7gzy73WaZ2MEopQp2fV5AohLeqaAoV6nx/xVq+kH9sAGKaH4qZ78s4pETjbffhT67+2hs20W5A4KJiH5y3gyd7fe6NKlulpdwtFzGl88VxNvpEEnITo4gbXmnmsr8ygIv8n3g91w2QrdIzkQn0ufjy3bw==
|
||||
GWDYUI0c8Ct3i6L4tejkFH+T+usUscBWHul4+WUmgwbOzbAkPgcaVWU00rXS/6TINxRI9WPCNgbBpH3y0BmNIlDXzXFXd8smuo4pyHtd6TXp+IWr6p1Yms4KzV7K+7d9
|
||||
LiVO4OAZQ41GCrj1VFqy49tJnp9BlG/aec6OCmYKY+09xxIr6eMh2alPog27Xzy1z2oKXLS73HcJeh1hUDN7H85yZJB5KxuBlzR2QZnnv/WK+a3HqEG2/aHMlFkAVe3Esv/bm7MQwzNHTVwwyX4+6N+/zduqbDASrbgp8JW6r5U8s+FwOGJKV3Reqnqs+/XncY8o8wAEYx8at6gS1KqPmr0887m7q3O+Ee7ToQpXAfZjupafNVMg8Y8z1mpq7au2
|
||||
LiVO4OAZQ41GCrj1VFqy49tJnp9BlG/aec6OCmYKY+39fBu+1OUNo9hSWZFf45Fcr6iPppgD4DcuTJOEcdbftxfoxWo+dL7xmuaL72fiDyJXXIbckZwwxve32cXNdfbkRrzY5+C6FmNBvbKFIVZHoA==
|
||||
LiVO4OAZQ41GCrj1VFqy49tJnp9BlG/aec6OCmYKY+1n2xOSacmX62EVJC46g/rjd6q6leIqAfA2wvM9hBNUnsUjYma72h95TF0VScg5YB/mF3paIQlxoFvcT9133xB0byBDM3NyEvDFj3YDOsQIzA==
|
||||
LiVO4OAZQ41GCrj1VFqy40xXTJtMuJpqKqDGzO//HWCYHnWQl+/6dVTnz8Uv/mP3KmU2LGm9S9Y68bkk6wUkdrOAEmwaqRGxgGr4fpcThJo3C8cyEwdyh/XtjLf+FpGV2WAR9PWURWOjY+3Dsv/AZJYvWnrAn0zEx2VtrCjwEzW6kWWTTynhagWnOHllrPEmWkZfNHCg5BgDtz8zp+oNUA==
|
||||
6S1DTW1TCVbUfeFz1/zAP8MlMUQ+iq+gDP31FgA75hZF23hEP2cwNRG64dw0lVR68qDE3/oN8uznLfLYYOujJRyjCktuJsEmBB7fgUvhf6KfqI2UVTxHqF9WT82gADkW
|
||||
fnnuZD0QAdxvV2PveMWL8MnPURZP7EzUIFSNSkR/DP3nRYXb0fUDE4U7M1r3zRQtQl7HxMPsKK69DQPV524wlWgMtz+Ny/G0Pe5DM3zxSvEXMEiQRG9A/Zj7S8KL6NnajyFMooBUqX66G8CR8bMScicsJ75E0Yd9Cze0RNKU9Wza3aIdiEmdkoJJHprWviuT
|
||||
oacxXEoPih9NKsd5qduwcBiuy7u2Ow2MIJfCF1pBvq+l5eyzjf2YC17f5yyPsixULDkW15S/zqjX1ADtgbpcxaPhfDdsZoOAh4jgcFf2hLfK5yksS8k7tRsztEy/dLNF1rwP1aVLBoDTQCcVq4DrJQEM40DKF8m5PpGaChnts2mp/Acv07Y+1SGRblH0AiyrFhwdzM31v3+snTzxybhzqh3fcofAFa/1YdUVAUvETCuO9MReNXR/ti5B4CEPZcu1CVDXm0iCcoCE2zgQZBAFl94T2Cum0QSYBb0+iro9jd/nItGRClUCZa1bTCuqbX/O8d6o77kuW416R/Ylj7EogtYaTw+Nj7s4g7j3vFgNlzDarsz+8doOepdfvAEN4+BOfX0kFvzsGw+BZvhVQsiFdYe5vtFiL2iELYzBnoDcptzwmqgcgyDVVOsMynvbIjFPM1zF1gxYKs63V9iT5VO4yFXtAf87QNjvvyitSpTdIoDijHo5xNeCCIz586+rNedRp/92kdW+Soi4SKEHSO3+myTZEV9rgTwzVT+nb7xcD7j/TBg/LIl1rnEh9xXfubdPmGA3DVwS7bWo3OHWlBhKyvBfqQcsIcvV80+2O3MHeYFuF28roWFw6QhGfFGcHoCrwgaukoJVKuJgHNrirJoelrvpKHC0QNwVRr73WlZSwyIh45/Ilyg3N/Sx6JET5iz080hktNKrJLUui0w7UBjTLGcQhAOJ/ExFiqD+shKGVW9ftIXrGPl2ycVtq0wWheMoHEu9MrFgZtep40pBjmDdMGAnm5vz6hsdVMz4OaJsBkAzvREbEuopcKwpMqP43by58DHGXoMCWk11oUN9ZBp8luaxd3USD64IzjhYzX4QzAwwzIY63UZD6hZDjEfYhnkn1gigyZrlX79BwIn6iSPu9cfTLgvUlrpRxzzfpLEa51s9uyt94ZoIJC2LRAIRCgTgCMG4xr6yLMNoSaTOcq7fd3SYvqRJKBfhli2wQlQ5jNKDwJI9aJc6ks7oOECKWrDB
|
||||
IL9sA67H0z06wFBWIR8QkaTnKJDOXWBfh9EK16Yt5HjpiShKLm24lByCsmMOp/+nm6sbfuAiTHANiUGCrj3O6YJUoGlXCUdJNawa7R4ydgTXxF1mtteD59hEDOyF5+eaneP8lM1d5A4NQGGoWiVG8g==
|
||||
NREvnNIDTttHan/FJweGj/msBpf/p1aKu8LZw94+KUqSn1c+F+iZlZgS/VL7fr/48X68sN6vyPH3CMR6/5oTo9qAC+Aq27vo62T00ZLfVanRZyH61IW97E6RRG1aY8G9PylFnqmEkg0hwE00IeHsj8B2FWSQPVs2IQsDmtv2d0jkn+EfMgHJJpItKcvIvvSjuTUXyAh+teqKf6BoWr1i9HmflGa+pBxysP8DY2jVav7fOiF26qxzGUTuyAkvh4bBiPPOkc1z0f2Kfh54NmOGmQ==
|
||||
yYOGmvXvGt/cRLLVkO4eKqa+hM3PuRZfD7b8rMYq/UT5o+JnFaIJw/yVufWRJ3GYE6JJV8UyWObkwgX0nomex4N7hMwH0p/mvytxHRM0LsXoHlzxAgZ68TlBXX9wMqO+
|
||||
NREvnNIDTttHan/FJweGj/msBpf/p1aKu8LZw94+KUqSn1c+F+iZlZgS/VL7fr/48X68sN6vyPH3CMR6/5oTo6pzILMLc9S2Abfp3x11erswXy+6aKQxkAOV3JNDJy/u4bISLULyNHieYZYXNxvYW/Dtf+nQ/d3q+8B6w+EKAiJUPNmPW8Mx5AGhPkKWWMQsz7ioFJ2CQjBvlTk/2hfy1MbIqtmWyx3r6g2Vvg1+UQ4ptd3QByZwW46+nwoFVVe7u8OdItBRe7okhek+hhTpiYfdw7mDXnQfcpCHAC7y4BjGXo0CurX7AjM06m7n6D1EA7tHc6gqHSOm5/cGUTKXig==
|
||||
yYOGmvXvGt/cRLLVkO4eKqa+hM3PuRZfD7b8rMYq/UT5o+JnFaIJw/yVufWRJ3GYE6JJV8UyWObkwgX0nomex4N7hMwH0p/mvytxHRM0LsXoHlzxAgZ68TlBXX9wMqO+
|
||||
CTDlCq/Yx3kXyawzsUjqPj/1UgvtLUwbSocBDSTGdlQdGlfuxYW1zktAmMlWajLEJlycf3QM6d3m2/8WV/7qap+0+9bbcfKO31Ha3+gfc0v/wa//RxuB/CTGHWThqgBLKsNaADG5PBVOlQNWxwKSNUS+55fKYqn7UbOGJUsBt08=
|
||||
iwvjn39WsWBJqN2zZdgrYH73io9UFYsVQIpyJHGNPolTowZ3ES6qaIlYZbd0+9c8k/3/kVFrQkiBM1cR8ZRiGoxZK4ShV6FY0bULRqyn93CV5P1j8chjs7oBotB9I/BtcUB3JYzsnV+37ppDY6xcDg==
|
||||
iwvjn39WsWBJqN2zZdgrYJapEN/AKnY2zLbcAIzyrBBU1RXGfgWqmb+6/1Y8honwoq8vQFNWL5QXG2xnJPe0LK1Ma+Uxp4BV2qI3ukXHtQYKXoJzDPI9GCy7FvK4NRqoVIY2d3UNJZ6JrGvDp8Itv8UtbTtOKRZzMGesfAFfpr8M2F7b1sde3FoHIbX53bIajKUCfv6EdR2qn5YyhmO/0Q==
|
||||
96orka/uERLyRst14azQwifX4NgxGrWxr0Kq7A5Rg2HnATx3FBLn85SCdMGIOm1E0hlma+GxHkgZc93eWmwVjA==
|
||||
6we+bQ+BNhpl74ICwbzDD6SJhA5UxkUBfCZmu1pDNmRCVuoiUdtV/LjGUcclBb9x1lO73/pbYlp7Qn7laP/ALybE3LW0N3KSwXGpr6c9FY4=
|
||||
cr04jPiHcZs6CKfXkpLJpg==
|
||||
fnnuZD0QAdxvV2PveMWL8FnhE/Qbu1TUcwt3ycoXzAb63R8Bw+Kjhj/s+Ugn6uM2VYtJ5GD3NvbvtZB/8CpMknz6mUrg1bAfFvVuTUch8Fa1XKdHthZX+SiOeT190cbuzf1PMxPOpzbt2lZhBmtWnV5tc/shXzdOMbVzBF3CVbwpT3MP6rpratp4mnHz3RuO
|
||||
SE5xU/Z0JSLRg+BF0JZlQ351DCSneiU0Ro4ul8s6YQ0+e9ClxvBwl8Z8jDAAh4Pw29EBMojpWeiQDQQ3je1JBQ==
|
||||
ncUn2TP8ZQ4fZMBYk+CUrbejaOCU8cNhJKyCBZWCqq3ZxbWlzmOTv+kBIJsZsjljcT1q3oO0cOKLsE5F65U+psAkCkXFw1+rnPdHpl45RtMkIcHFBbTnubK1Yw2j5SiSMTQaANcjGIXkA5pbNDFojl1kkOkaPHt6uO54XZwjB9PlZ8XdctMBp+wpTD06crdB
|
||||
R6vHhJwn2j7IZ8/oBXXPlciOa3G4bauQKWbklU12JP0CWdxdVaZIoNzpWfrmbe5i5gswcTWd6DqXeLXmYLSydw==
|
||||
wgR07xfoapmx6eEnFHXXYv6sj3jsGK5jp+XNGADM1YwZ3X8erO8tF+9rF+ud3CmG2DzTMUCy19ltKZJBZVeJ2G3b7Y/tUzeVbHaaGaNkyQryOXyVCJelyU3NO9pBJXZwU4csk3bxLN74sMPi17loDmo4qNbgIL5dTT7IV6iCpcJf45etCMNP7ojLR/iLdfFt
|
||||
ut2tmPKYoa0Hz0cuVsUj3l2A/S9h8YCNZoTpXi3WyNmbvxKV9hRgROXsqHqZmvm0sTMN+4iSaKr2yT/X+fgBC4YDIVZ1uBFHcV7UgCMzOjI2lx9+St+VE5ivldn9lPHV3rb5YkHv11D4TUNLk3DCWm7kTSih4pt3xjcF9tbSGek=
|
||||
ut2tmPKYoa0Hz0cuVsUj3iSUOfYfZogjpziC8PUGLSE9MjZBw4GuEUF0vb4KA4CRuxc4tpvehR3tbZvfDCzpxJksbJGmNWFIh7s9WlNnDc+qD7wQpCT3NbfBgRmblirSNOVpyIgLflRUGrvOFeOG9zFm3PjGlOZ00Vv3qWkURL8=
|
||||
oF+52jOqU38B3IbYFCrd4N3GYJGn+k9zqnS5QNsGjaRnqfzqGwgeL+xZ/I7WiPbOLIGF8wwQthufZuWJLZ8TV8PVM+kG0CKewnf99F2dx5s=
|
||||
p4mlb5HXUU40EYWFAnjifyb31sUX+0BXv/YW9j2K+gI=
|
||||
8qTxQznEcsQMgFW26Dqik37xPQpnAepb+3VTmXSvTHkBXZvjIZwIqQeUzzujDsnU8/MAPAbj2oDa9K3AqwPTFQ==
|
||||
2wtz2EJ9gcVOn6ULRb1bGDulJXIx4y56v5IQGpDjYFZ136nD/ZkugeoB6wP9mFEheXByEOtBdpbVts7POYAC1Q==
|
||||
VmVrGQo2zRokW/ZuO9bN60HnLn+7qb3BEYgduIkYBusMNq2qQ2m7PTCE41vqIcK/Cewvi49S3FU5bVmsIU/TRg==
|
||||
VmVrGQo2zRokW/ZuO9bN66B2cWRLetUcWMU+aw+SZbQ=
|
||||
fnnuZD0QAdxvV2PveMWL8GzimDATsb9PCxhUZX36WPceYPd8+C+DZiTdw0oWYeDzPAREthfc0Ab+8X6ybl3VEmmQvWGs9zAYVneC2Hy2egkTCe1Ob78xdnB0S18HF60ZIM1v7YQAQ8UB+CC4cZs7fQ==
|
||||
AaCYXSBoNzzxOXBdbJWxCI9qK/O2dxQuwFCqR22/ccmrRlWPB13BOQzWf+aWkGS+2+eb+G2UGJ030Ldkc/TRa6QakPcSXSNOI3gUmbZsFE56ZNHp130Cn7JwRwpSNvyF
|
||||
Igyj+TKK+I9SELYdi+D74wrFQ1TlNAWhWGzDssoXLbghxc1cj/mwrtUBlQ6VRLTuoSRRar3R+eQrcrTodxnolxO11AHYzchAkrT97uXxfomkpOzQL5Tmlw5oI/hsnk0R3C+lgPstP5/4bDc90+iRQT3cMxKnuQv1rM9z6oW2nPBssswhEAPdwxcmplZu4C3JnPxdZByVx6FbRN2Jgg4Y1CUhjhiIBddhAyjAv1YWNpTM8o5GlDeqrvWm2293br1F
|
||||
Igyj+TKK+I9SELYdi+D74wrFQ1TlNAWhWGzDssoXLbjeoHs/8Mje8tsYdNHFBscqwQug2YW9a6jBvQV2kMslbbKaz2EQLgEjn6frBGO4TfxHRuA1CCfJmWabVkIQMFxrCJix3c+0lMgO1+8zPIjvrg==
|
||||
Igyj+TKK+I9SELYdi+D74wrFQ1TlNAWhWGzDssoXLbiZex8VHIziY50edMtwBriCkbhwV2pZ9K3FDuHuJkHYxeLxgByj1SOSg2vK7OLlpEhM2jDZRUpXVynPlw8R1bP7ZLPJI+hMXZWTM2qTMVW4Bg==
|
||||
1cV64uRoDtvn/9K8xFmBBSyIwLLAyZtDmWjNCGSK35oV7Lln1obVdrK86aC2P/5d2IugIo65luFTN3ITzWeIAojASipLuDAxR0vKGzse+0ZM659ojBqm1tuvWsd/P5Hs8sc9RblCikWUy4X3c3w5R9/jB0lLIJ44vKAW2Z/MoB4f+A5ULgHqCz5/JSrpUeMfl/E8YVza9ME/7/ufufeoNA==
|
||||
/wrjOJbIgR3iizz9ZfsYFV1S0QEoNDYDB0tPgYYyunCzrR8+mwbHh2ZHlRO+dgFF1df50fLmTkW5bI44PHknwmKwbKoYj8Y9Uyhuh9nMKzL8yi5sZyw9SFrwXay2nHnR
|
||||
fnnuZD0QAdxvV2PveMWL8DHcrBrw7XfIoGItmS/X1LRvez55+VhH4ORJHoks3tPiigwsWjzGIQ1+EqGmE/pzsSG8L1Qo4r3de+ZwnWu4x5aYGJBCnAtBWXOAjrBM7bRdQX4XYwovgtmfpuO6eZBDlcrPlsAE0RxjrJ/E/BsdBTRGuen7gVcgLjFTZvWMO4Fa
|
||||
oacxXEoPih9NKsd5qduwcLPkuMecFSQLme+U3RYD4k6vG2vB69hZeZTj75RiG2qUS2vKp6FFekTp22dTzpmqrhqwF3gZSut9skRswVAOd+ey+p8hkk31WVViZKUsvFoZcQzf5qFZ5bMTM/a7hA53WqJlzxxMkdA2km9UpRf8a2WRvbBa6KD/jTkeYiZl/nHyHjmA2tqxhDLike6xDAbA2AQYYTbkiirIVH9/A+P08TmTNHCZUryZAOMBqpffFuhKa4uoh4D0WBbjEPrFdoiEz3ocw5bKhTwdKD2RQWcIFihi+UnmV2ApR3o26gPYgi6HRSeiKrZEwhcp5m+whI7lnng5/abuOGGbabfAagwFRP8HkguHuJ2vfjmYtJiVXkgrpjYSJsDZHFwhgfPxj9XqVRNzREoMxO0S/b0FC90Z6w0r1eMRmzBF5N2Zn/4JOzfvVymJ+MEoKHZyQjjwZIIOXp4KFKnmvUZ9q4C//bBvwEaBQJ6Qteg7RZ0QQkafEG/NBncU1vOMCYFIZTOG/ym+H39xC51Omll5vt64U6rtJO7lsIO+WKd9WZAUYATPv1J1g1aRzsJycWilmD+jWXpI23ZcbmmTf4VctIpeCNZwnm+aQm7J30HLgU2PnkluZdq744bQ4GCZQVgHkLM++NGVUmDB97Rx/4FIZ9i83MNYpndJPYOe2yYnQ5vThEHFeanLo115DYYct09qBrRVGeM9hxfN7UP1MWDKFeAbZF5flQE=
|
||||
nPNZk+Xvg1c6GZFzrp1IbMVt0EpHjdQMD/KiHv3lEICoTqIbAmvUQ+gVypzCdBB8Gs0AbP+Zh9pMLpuFBMJVhrRL3RKTfSSRfVHFNiMAjiuK48g7qWvs2jmegZXfmVGc+gXJ9imIODTMBbyPmgyrR0qZFdlSN4+ocHLB0gjsQGmIRDYaJNrNAnS4USkTNOXVJ+CnobHbEUrDvenXe4GcGwb6lwpI0j1vr6tVraqgemOc+yVhnFDBFX0eaTQPMUsDqeqEbxv/r/mhMEfOmRGhUA==
|
||||
wu62rpGT52ZTxeUUs2GeuGgAZsk/tzh/isMkRRQuL7nq3eaiw1Qb9M0+Qc8KElN+7mEiLyeftYZBbZDOnzNciRm5TdJahLGV1drbGS1rn8dSqfam6zfdyDZ+0qHR+jnX
|
||||
nPNZk+Xvg1c6GZFzrp1IbMVt0EpHjdQMD/KiHv3lEICoTqIbAmvUQ+gVypzCdBB8Gs0AbP+Zh9pMLpuFBMJVhlpvc3VMIX/ToG+YV/rNHgA6KSwDvFN3sEa/wtjnlB7Gwj6zOH2itskLF4HrIvxMLthUmGUfGpnVqtHOpKzBOhMdQMK3ECYTLkqJgqQIjZkxcxvKH33BB8iIKHhbL/7VeuzthB99YJSe3mQ0vuX2vvcBZTIlX/khXl8eo63Qod7ozf7o47f41YKmUdwsO/JMXjeiD0NMGOFxwR4AREJ50Invb5AF4D9pp2kJTvEUlKGD+L4b4hSYjM37qFKD1zXD1A==
|
||||
wu62rpGT52ZTxeUUs2GeuGgAZsk/tzh/isMkRRQuL7nq3eaiw1Qb9M0+Qc8KElN+7mEiLyeftYZBbZDOnzNciRm5TdJahLGV1drbGS1rn8dSqfam6zfdyDZ+0qHR+jnX
|
||||
8qTxQznEcsQMgFW26Dqik37xPQpnAepb+3VTmXSvTHkBXZvjIZwIqQeUzzujDsnU8/MAPAbj2oDa9K3AqwPTFQ==
|
||||
2wtz2EJ9gcVOn6ULRb1bGDulJXIx4y56v5IQGpDjYFZ136nD/ZkugeoB6wP9mFEheXByEOtBdpbVts7POYAC1Q==
|
||||
VmVrGQo2zRokW/ZuO9bN65CLqRUEWJ03MnVfT48m2QyxHgYbgNM+mUWp/RHlScL707Hwd5hAXrcCQuNOHzWRmw==
|
||||
VmVrGQo2zRokW/ZuO9bN66B2cWRLetUcWMU+aw+SZbQ=
|
||||
iwvjn39WsWBJqN2zZdgrYG5NBDXw/UERaMa5qn6uxHIlNsNh7PeHEY5YZ4B/EHd4pgIscKVIIX7ioUSholIaIyLKidrEOF20CDJX/iz34wBbW9zWqoCbzoD6tzk7oYnY1Lb5dkZX86F/rOGlcmjsIQ==
|
||||
iwvjn39WsWBJqN2zZdgrYJapEN/AKnY2zLbcAIzyrBAAFOSsyeU1IHqhRAAJmxek18L8hhYV0nclwoNTInf9BxJ1mKeAbWt9n4txx96fjdNoTICL7WaSPRAd+PHZ9Rckg0kFG02IFUMdzt0r5RApu6mM0z1QqDZmZc2kp00MWUTfdnwFkK6MLDk+Drcqk5fnWaio6MEpLq2BY4/d9cl99Q==
|
||||
96orka/uERLyRst14azQwifX4NgxGrWxr0Kq7A5Rg2GgtWLCloikT548er10NVqyOU/URIs3U0nX+iki5Rj91UImIzSUQ3706pgDdxepy+E=
|
||||
Reference in New Issue
Block a user