77import subprocess
88import threading
99import traceback
10- from functools import partial
1110
1211import paramiko
1312import sympy
1918from bibigrid .core .utility import image_selection
2019from bibigrid .core .utility .handler import ssh_handler
2120from bibigrid .core .utility .paths import ansible_resources_path as a_rp
22- from bibigrid .core .utility .paths import bin_path
21+ from bibigrid .core .utility .paths .basic_path import CLUSTER_INFO_FOLDER , KEY_FOLDER , CLUSTER_MEMORY_PATH
22+ from bibigrid .core .utility .statics .create_statics import AC_NAME , KEY_NAME , DEFAULT_SECURITY_GROUP_NAME , \
23+ WIREGUARD_SECURITY_GROUP_NAME , MASTER_IDENTIFIER , WORKER_IDENTIFIER , \
24+ VPNGTW_IDENTIFIER , UPLOAD_FILEPATHS
2325from bibigrid .models import exceptions
2426from bibigrid .models import return_threading
2527from bibigrid .models .exceptions import ExecutionException , ConfigurationException
2628
27- PREFIX = "bibigrid"
28- SEPARATOR = "-"
29- PREFIX_WITH_SEP = PREFIX + SEPARATOR
30- FILEPATHS = [(a_rp .PLAYBOOK_PATH , a_rp .PLAYBOOK_PATH_REMOTE ), (bin_path .BIN_PATH , bin_path .BIN_PATH_REMOTE )]
31-
32-
33- def get_identifier (identifier , cluster_id , additional = "" ):
34- """
35- This method does more advanced string formatting to generate master, vpngtw and worker names
36- @param identifier: master|vpngtw|worker
37- @param cluster_id: id of cluster
38- @param additional: an additional string to be added at the end
39- @return: the generated string
40- """
41- general = PREFIX_WITH_SEP + identifier + SEPARATOR + cluster_id
42- if additional or additional == 0 :
43- return general + SEPARATOR + str (additional )
44- return general
45-
46-
47- MASTER_IDENTIFIER = partial (get_identifier , identifier = "master" , additional = "" )
48- WORKER_IDENTIFIER = partial (get_identifier , identifier = "worker" )
49- VPN_WORKER_IDENTIFIER = partial (get_identifier , identifier = "vpngtw" )
50-
51- KEY_PREFIX = "tempKey_bibi"
52- CONFIG_FOLDER = os .path .expanduser ("~/.config/bibigrid/" )
53- KEY_FOLDER = os .path .join (CONFIG_FOLDER , "keys/" )
54- AC_NAME = "ac" + SEPARATOR + "{cluster_id}"
55- KEY_NAME = KEY_PREFIX + SEPARATOR + "{cluster_id}"
56- CLUSTER_MEMORY_FOLDER = KEY_FOLDER
57- CLUSTER_MEMORY_FILE = ".bibigrid.mem"
58- CLUSTER_MEMORY_PATH = os .path .join (CONFIG_FOLDER , CLUSTER_MEMORY_FILE )
59- DEFAULT_SECURITY_GROUP_NAME = "default" + SEPARATOR + "{cluster_id}"
60- WIREGUARD_SECURITY_GROUP_NAME = "wireguard" + SEPARATOR + "{cluster_id}"
61-
6229
6330class Create : # pylint: disable=too-many-instance-attributes,too-many-arguments
6431 """
@@ -103,6 +70,22 @@ def __init__(self, *, providers, configurations, config_path, log, debug=False,
10370 "useMasterWithPublicIp" , True )
10471 self .log .debug ("Keyname: %s" , self .key_name )
10572
73+ os .makedirs (os .path .join (CLUSTER_INFO_FOLDER ), exist_ok = True )
74+ self .write_cluster_state ({"floating_ip" : None , "state" : 202 ,
75+ "message" : "Create process has been started." })
76+
77+ def write_cluster_state (self , state ):
78+ state = {"cluster_id" : self .cluster_id , "ssh_user" : self .ssh_user , ** state }
79+ # last cluster
80+ with open (CLUSTER_MEMORY_PATH , mode = "w+" , encoding = "UTF-8" ) as cluster_memory_file :
81+ yaml .safe_dump (data = state , stream = cluster_memory_file )
82+ # all clusters
83+ cluster_info_path = os .path .normpath (os .path .join (CLUSTER_INFO_FOLDER , f"{ self .cluster_id } .yaml" ))
84+ if not cluster_info_path .startswith (os .path .normpath (CLUSTER_INFO_FOLDER )):
85+ raise ValueError ("Invalid cluster_id resulting in path traversal" )
86+ with open (cluster_info_path , mode = "w+" , encoding = "UTF-8" ) as cluster_info_file :
87+ yaml .safe_dump (data = state , stream = cluster_info_file )
88+
10689 def create_defaults (self ):
10790 self .log .debug ("Creating default files" )
10891 if not self .configurations [0 ].get ("customAnsibleCfg" , False ) or not os .path .isfile (a_rp .ANSIBLE_CFG_PATH ):
@@ -138,10 +121,6 @@ def generate_keypair(self):
138121 for provider in self .providers :
139122 provider .create_keypair (name = self .key_name , public_key = public_key )
140123
141- # write cluster_id to automatically read it on following calls if no cid is given
142- with open (CLUSTER_MEMORY_PATH , mode = "w+" , encoding = "UTF-8" ) as cluster_memory_file :
143- yaml .safe_dump (data = {"cluster_id" : self .cluster_id , "ssh_user" : self .ssh_user }, stream = cluster_memory_file )
144-
145124 def delete_old_vars (self ):
146125 """
147126 Deletes host_vars and group_vars
@@ -238,14 +217,14 @@ def start_vpn_or_master(self, configuration, provider): # pylint: disable=too-m
238217 raise ConfigurationException (f"MAC address for ip { configuration ['private_v4' ]} not found." )
239218
240219 # pylint: disable=comparison-with-callable
241- if identifier == VPN_WORKER_IDENTIFIER or (identifier == MASTER_IDENTIFIER and self .use_master_with_public_ip ):
220+ if identifier == VPNGTW_IDENTIFIER or (identifier == MASTER_IDENTIFIER and self .use_master_with_public_ip ):
242221 configuration ["floating_ip" ] = \
243222 provider .attach_available_floating_ip (network = external_network , server = server )["floating_ip_address" ]
244223 if identifier == MASTER_IDENTIFIER :
245- with open ( CLUSTER_MEMORY_PATH , mode = "w+" , encoding = "UTF-8" ) as cluster_memory_file :
246- yaml . safe_dump (
247- data = { "cluster_id " : self . cluster_id , "floating_ip" : configuration [ "floating_ip" ]},
248- stream = cluster_memory_file )
224+ self . write_cluster_state ({ "cluster_id" : self . cluster_id , "floating_ip" : configuration [ "floating_ip" ],
225+ "state" : 202 ,
226+ "message " : "Create process has been started. Master has been created."
227+ } )
249228 self .log .debug (f"Added floating ip { configuration ['floating_ip' ]} to { name } ." )
250229 elif identifier == MASTER_IDENTIFIER :
251230 configuration ["floating_ip" ] = server ["private_v4" ] # pylint: enable=comparison-with-callable
@@ -303,12 +282,13 @@ def create_server_volumes(self, provider, instance, name):
303282 @param name: sever name
304283 @return:
305284 """
306- self .log .info ("Creating volumes ..." )
285+ self .log .info (f "Creating volumes for { name } ..." )
307286 return_volumes = []
308-
309287 group_instance = {"volumes" : []}
310288 instance ["group_instances" ] = {name : group_instance }
289+
311290 for i , volume in enumerate (instance .get ("volumes" , [])):
291+ self .log .debug (f"Volume { i } : { volume } " )
312292 if not volume .get ("exists" ):
313293 if volume .get ("permanent" ):
314294 infix = "perm"
@@ -332,10 +312,10 @@ def create_server_volumes(self, provider, instance, name):
332312 if not return_volume :
333313 raise ConfigurationException (f"Snapshot { volume ['snapshot' ]} not found!" )
334314 else :
335- self .log .debug ("Creating volume..." )
336315 return_volume = provider .create_volume (name = volume_name , size = volume .get ("size" , 50 ),
337316 volume_type = volume .get ("type" ),
338317 description = f"Created for { name } " )
318+ self .log .info (f"Volumes { i } created for { name } ..." )
339319 return_volumes .append (return_volume )
340320 return return_volumes
341321
@@ -382,7 +362,7 @@ def prepare_vpn_or_master_args(self, configuration):
382362 identifier = MASTER_IDENTIFIER
383363 elif configuration .get ("vpnInstance" ):
384364 instance_type = configuration ["vpnInstance" ]
385- identifier = VPN_WORKER_IDENTIFIER
365+ identifier = VPNGTW_IDENTIFIER
386366 else :
387367 self .log .warning (
388368 f"Configuration { configuration ['cloud_identifier' ]} "
@@ -464,7 +444,8 @@ def upload_data(self, private_key, clean_playbook=False):
464444 ssh_handler .execute_ssh (ssh_data = ssh_data , log = self .log )
465445 self .log .info ("Uploading Data" )
466446 ssh_data = {"floating_ip" : self .master_ip , "private_key" : private_key , "username" : self .ssh_user ,
467- "commands" : commands , "filepaths" : FILEPATHS , "gateway" : self .configurations [0 ].get ("gateway" , {}),
447+ "commands" : commands , "filepaths" : UPLOAD_FILEPATHS ,
448+ "gateway" : self .configurations [0 ].get ("gateway" , {}),
468449 "timeout" : self .ssh_timeout }
469450 ssh_handler .execute_ssh (ssh_data = ssh_data , log = self .log )
470451
@@ -592,6 +573,9 @@ def create(self): # pylint: disable=too-many-branches,too-many-statements
592573 else :
593574 return 0 # will be called if no exception occurred
594575 terminate .terminate (cluster_id = self .cluster_id , providers = self .providers , log = self .log , debug = self .debug )
576+ self .write_cluster_state ({"floating_ip" : self .configurations [0 ]["floating_ip" ],
577+ "state" : 500 ,
578+ "message" : "Cluster creation failed. Terminated remains." })
595579 return 1
596580
597581 def log_cluster_start_info (self ):
@@ -616,3 +600,6 @@ def log_cluster_start_info(self):
616600 self .log .log (42 , f"Detailed cluster info: ./bibigrid.sh -i '{ self .config_path } ' -l -cid { self .cluster_id } " )
617601 if self .configurations [0 ].get ("ide" ):
618602 self .log .log (42 , f"IDE Port Forwarding: ./bibigrid.sh -i '{ self .config_path } ' -ide -cid { self .cluster_id } " )
603+ self .write_cluster_state ({"floating_ip" : self .configurations [0 ]["floating_ip" ],
604+ "state" : 201 ,
605+ "message" : "Cluster successfully created." })
0 commit comments