Skip to content

Commit 19437d2

Browse files
authored
Merge branch 'dev' into 595/Update_Zabbix
2 parents d9482b8 + 25aa555 commit 19437d2

File tree

21 files changed

+174
-87
lines changed

21 files changed

+174
-87
lines changed

bibigrid.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# For an easy introduction see https://github.com/deNBI/bibigrid_clum
2-
# For more detailed information see https://github.com/BiBiServ/bibigrid/blob/master/documentation/markdown/features/configuration.md
1+
# For an easy introduction see https://github.com/deNBI/bibigrid_clum
2+
# For more detailed information see https://github.com/BiBiServ/bibigrid/blob/master/documentation/markdown/features/configuration.md
33

44
- # -- BEGIN: GENERAL CLUSTER INFORMATION --
55
# The following options configure cluster wide keys
@@ -123,4 +123,4 @@
123123
# terminate: True # whether the volume is terminated on server termination
124124
# size: 50
125125

126-
#- [next configurations]
126+
# - [next configurations]

bibigrid/core/actions/create.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
The cluster creation (master's creation, key creation, ansible setup and execution, ...) is done here
33
"""
44

5+
import os
56
import shutil
67
import subprocess
78
import threading
89
import traceback
9-
import os
1010

1111
import paramiko
1212
import sympy
@@ -17,13 +17,14 @@
1717
from bibigrid.core.utility import id_generation
1818
from bibigrid.core.utility import image_selection
1919
from bibigrid.core.utility.handler import ssh_handler
20-
from bibigrid.models import exceptions
21-
from bibigrid.models import return_threading
22-
from bibigrid.models.exceptions import ExecutionException, ConfigurationException
2320
from bibigrid.core.utility.paths import ansible_resources_path as a_rp
21+
from bibigrid.core.utility.paths.basic_path import CLUSTER_INFO_FOLDER, KEY_FOLDER, CLUSTER_MEMORY_PATH
2422
from bibigrid.core.utility.statics.create_statics import AC_NAME, KEY_NAME, DEFAULT_SECURITY_GROUP_NAME, \
25-
WIREGUARD_SECURITY_GROUP_NAME, KEY_FOLDER, CLUSTER_MEMORY_PATH, MASTER_IDENTIFIER, WORKER_IDENTIFIER, \
23+
WIREGUARD_SECURITY_GROUP_NAME, MASTER_IDENTIFIER, WORKER_IDENTIFIER, \
2624
VPNGTW_IDENTIFIER, UPLOAD_FILEPATHS
25+
from bibigrid.models import exceptions
26+
from bibigrid.models import return_threading
27+
from bibigrid.models.exceptions import ExecutionException, ConfigurationException
2728

2829

2930
class Create: # pylint: disable=too-many-instance-attributes,too-many-arguments
@@ -69,6 +70,22 @@ def __init__(self, *, providers, configurations, config_path, log, debug=False,
6970
"useMasterWithPublicIp", True)
7071
self.log.debug("Keyname: %s", self.key_name)
7172

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+
7289
def create_defaults(self):
7390
self.log.debug("Creating default files")
7491
if not self.configurations[0].get("customAnsibleCfg", False) or not os.path.isfile(a_rp.ANSIBLE_CFG_PATH):
@@ -104,10 +121,6 @@ def generate_keypair(self):
104121
for provider in self.providers:
105122
provider.create_keypair(name=self.key_name, public_key=public_key)
106123

107-
# write cluster_id to automatically read it on following calls if no cid is given
108-
with open(CLUSTER_MEMORY_PATH, mode="w+", encoding="UTF-8") as cluster_memory_file:
109-
yaml.safe_dump(data={"cluster_id": self.cluster_id, "ssh_user": self.ssh_user}, stream=cluster_memory_file)
110-
111124
def delete_old_vars(self):
112125
"""
113126
Deletes host_vars and group_vars
@@ -208,10 +221,10 @@ def start_vpn_or_master(self, configuration, provider): # pylint: disable=too-m
208221
configuration["floating_ip"] = \
209222
provider.attach_available_floating_ip(network=external_network, server=server)["floating_ip_address"]
210223
if identifier == MASTER_IDENTIFIER:
211-
with open(CLUSTER_MEMORY_PATH, mode="w+", encoding="UTF-8") as cluster_memory_file:
212-
yaml.safe_dump(
213-
data={"cluster_id": self.cluster_id, "floating_ip": configuration["floating_ip"]},
214-
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+
})
215228
self.log.debug(f"Added floating ip {configuration['floating_ip']} to {name}.")
216229
elif identifier == MASTER_IDENTIFIER:
217230
configuration["floating_ip"] = server["private_v4"] # pylint: enable=comparison-with-callable
@@ -560,6 +573,9 @@ def create(self): # pylint: disable=too-many-branches,too-many-statements
560573
else:
561574
return 0 # will be called if no exception occurred
562575
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."})
563579
return 1
564580

565581
def log_cluster_start_info(self):
@@ -584,3 +600,6 @@ def log_cluster_start_info(self):
584600
self.log.log(42, f"Detailed cluster info: ./bibigrid.sh -i '{self.config_path}' -l -cid {self.cluster_id}")
585601
if self.configurations[0].get("ide"):
586602
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."})

bibigrid/core/actions/terminate.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,25 @@
77
import re
88
import time
99

10+
import yaml
11+
12+
from bibigrid.core.utility.paths.basic_path import CLUSTER_INFO_FOLDER, CLUSTER_MEMORY_PATH, KEY_FOLDER
1013
from bibigrid.core.utility.statics.create_statics import DEFAULT_SECURITY_GROUP_NAME, WIREGUARD_SECURITY_GROUP_NAME, \
11-
KEY_NAME, KEY_FOLDER, AC_NAME
14+
KEY_NAME, AC_NAME
1215
from bibigrid.models.exceptions import ConflictException
1316

1417

18+
def write_cluster_state(cluster_id, state):
19+
# last cluster
20+
with open(CLUSTER_MEMORY_PATH, mode="w+", encoding="UTF-8") as cluster_memory_file:
21+
yaml.safe_dump(data=state, stream=cluster_memory_file)
22+
# all clusters
23+
cluster_info_path = os.path.normpath(os.path.join(CLUSTER_INFO_FOLDER, f"{cluster_id}.yaml"))
24+
if not cluster_info_path.startswith(CLUSTER_INFO_FOLDER):
25+
raise ValueError("Invalid cluster_id resulting in path traversal")
26+
with open(cluster_info_path, mode="w+", encoding="UTF-8") as cluster_info_file:
27+
yaml.safe_dump(data=state, stream=cluster_info_file)
28+
1529
def terminate(cluster_id, providers, log, debug=False, assume_yes=False):
1630
"""
1731
Goes through all providers and gets info of all servers which name contains cluster ID.
@@ -230,6 +244,8 @@ def terminate_output(*, cluster_server_state, cluster_keypair_state, cluster_sec
230244
cluster_keypair_deleted = all(cluster_keypair_state)
231245
cluster_security_group_deleted = all(cluster_security_group_state)
232246
cluster_volume_deleted = all(all(instance_volume_states) for instance_volume_states in cluster_volume_state)
247+
message = "Cluster terminated."
248+
state = 200
233249
if cluster_existed:
234250
if cluster_server_terminated:
235251
log.info("Terminated all servers of cluster %s.", cluster_id)
@@ -249,18 +265,27 @@ def terminate_output(*, cluster_server_state, cluster_keypair_state, cluster_sec
249265
log.warning("Unable to delete all volumes of cluster %s.", cluster_id)
250266
if (cluster_server_terminated and cluster_keypair_deleted and cluster_security_group_deleted and
251267
cluster_volume_deleted):
252-
log.log(42, f"Successfully terminated cluster {cluster_id}.")
268+
message = f"Successfully terminated cluster {cluster_id}."
269+
log.log(42, message)
253270
else:
254-
log.warning("Unable to terminate cluster %s properly."
255-
"\nAll servers terminated: %s"
256-
"\nAll keys deleted: %s"
257-
"\nAll security groups deleted: %s"
258-
"\nAll volumes deleted: %s", cluster_id, cluster_server_terminated,
259-
cluster_keypair_deleted, cluster_security_group_deleted, cluster_volume_deleted)
271+
message = (f"Unable to terminate cluster {cluster_id} properly."
272+
f"\nAll servers terminated: {cluster_server_terminated}"
273+
f"\nAll keys deleted: {cluster_keypair_deleted}"
274+
f"\nAll security groups deleted: {cluster_security_group_deleted}"
275+
f"\nAll volumes deleted: {cluster_volume_deleted}")
276+
log.warning(message)
260277
if ac_state:
261278
log.info("Successfully handled application credential of cluster %s.", cluster_id)
262279
else:
263280
log.warning("Unable to delete application credential of cluster %s", cluster_id)
264281
else:
265-
log.warning("Unable to find any servers for cluster-id %s. "
266-
"Check cluster-id and configuration.\nAll keys deleted: %s", cluster_id, cluster_keypair_deleted)
282+
message = "Cluster does not exist."
283+
state = 404
284+
log.warning(f"Unable to find any servers for cluster-id {cluster_id}. "
285+
f"Check cluster-id and configuration.\nAll keys deleted: {cluster_keypair_deleted}")
286+
287+
write_cluster_state(cluster_id, {"cluster_id": cluster_id,
288+
"floating_ip": None,
289+
"ssh_user": None,
290+
"state": state,
291+
"message": message})

bibigrid/core/rest/models.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1-
from typing import List, Optional
2-
from pydantic import BaseModel, Field
1+
"""
2+
This module contains models used by the REST api
3+
"""
4+
5+
from typing import List, Optional, Literal
6+
from pydantic import BaseModel, Field, IPvAnyAddress
37

48

59
# pylint: disable=too-few-public-methods
610

711

812
class BootVolume(BaseModel):
13+
"""
14+
Holds information about where the server boots from
15+
"""
916
name: Optional[str]
1017
terminate: Optional[bool]
1118
size: Optional[int]
1219

1320

1421
class Volume(BaseModel):
22+
"""
23+
Holds volume/attached storage information
24+
"""
1525
name: Optional[str]
1626
snapshot: Optional[str]
1727
permanent: Optional[bool]
@@ -24,6 +34,9 @@ class Volume(BaseModel):
2434

2535

2636
class Instance(BaseModel):
37+
"""
38+
Holds instance/server information
39+
"""
2740
type: str
2841
image: str
2942
count: Optional[int]
@@ -35,19 +48,28 @@ class Instance(BaseModel):
3548

3649

3750
class UserRole(BaseModel):
51+
"""
52+
Allows users to add custom ansible roles
53+
"""
3854
hosts: List[str]
3955
roles: List[dict] # Replace 'dict' with more specific type if possible
4056
varsFiles: Optional[List[str]]
4157

4258

4359
class ElasticScheduling(BaseModel):
60+
"""
61+
Holds info on Slurms scheduling
62+
"""
4463
SuspendTime: Optional[int]
4564
SuspendTimeout: Optional[int]
4665
ResumeTimeout: Optional[int]
4766
TreeWidth: Optional[int]
4867

4968

5069
class SlurmConf(BaseModel):
70+
"""
71+
Holds info on basic Slurm settings
72+
"""
5173
db: Optional[str]
5274
db_user: Optional[str]
5375
db_password: Optional[str]
@@ -56,11 +78,17 @@ class SlurmConf(BaseModel):
5678

5779

5880
class Gateway(BaseModel):
81+
"""
82+
Holds info regarding whether a gateway is used to connect to the master
83+
"""
5984
ip: str
6085
portFunction: str
6186

6287

6388
class ConfigModel(BaseModel):
89+
"""
90+
Holds info regarding the configuration
91+
"""
6492
infrastructure: str
6593
cloud: str
6694
sshUser: str
@@ -95,6 +123,10 @@ class ConfigModel(BaseModel):
95123

96124

97125
class OtherConfigModel(ConfigModel):
126+
"""
127+
Holds info about other configurations
128+
TODO: Fill in the missing bits
129+
"""
98130
vpnInstance: Instance
99131

100132

@@ -141,9 +173,12 @@ class LogResponseModel(BaseModel):
141173
log: str
142174

143175

144-
class ReadyResponseModel(BaseModel):
176+
class ClusterStateResponseModel(BaseModel):
145177
"""
146-
ResponseModel for ready
178+
Response model for state
147179
"""
180+
cluster_id: str
181+
floating_ip: IPvAnyAddress
148182
message: str
149-
ready: bool
183+
ssh_user: str
184+
state: Literal[200, 201, 204, 404, 500]

bibigrid/core/startup_rest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from bibigrid.core.utility import id_generation
1919
from bibigrid.core.utility.handler import provider_handler
2020
from bibigrid.core.rest.models import ValidationResponseModel, CreateResponseModel, TerminateResponseModel, \
21-
InfoResponseModel, LogResponseModel, ReadyResponseModel
21+
InfoResponseModel, LogResponseModel, ClusterStateResponseModel
2222

2323
VERSION = "0.0.1"
2424
DESCRIPTION = """
@@ -248,7 +248,7 @@ async def get_log(cluster_id: str, lines: int = None):
248248
return JSONResponse(content={"error": str(exc)}, status_code=400)
249249

250250

251-
@app.get("/bibigrid/ready/", response_model=ReadyResponseModel)
251+
@app.get("/bibigrid/ready/", response_model=ClusterStateResponseModel)
252252
async def ready(cluster_id: str):
253253
"""
254254
Expects a cluster id.

bibigrid/core/utility/command_line_interpreter.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import logging
77
import os
88

9-
INPUT_PATH = "~/.config/bibigrid"
10-
STANDARD_CONFIG_INPUT_PATH = os.path.expanduser(INPUT_PATH)
9+
from bibigrid.core.utility.paths.basic_path import CONFIG_FOLDER
10+
1111
FOLDER_START = ("~/", "/")
1212
LOG = logging.getLogger("bibigrid")
1313

@@ -39,9 +39,9 @@ def interpret_command_line():
3939
"Offers termination after successful create")
4040
parser.add_argument("-i", "--config_input", metavar="<path>", help="Path to YAML configurations file. "
4141
"Relative paths can be used and start "
42-
f"at '{INPUT_PATH}'. "
42+
f"at '{CONFIG_FOLDER}'. "
4343
"Required for all actions but '--version'",
44-
type=lambda s: s if s.startswith(FOLDER_START) else os.path.join(STANDARD_CONFIG_INPUT_PATH, s))
44+
type=lambda s: s if s.startswith(FOLDER_START) else os.path.join(CONFIG_FOLDER, s))
4545
parser.add_argument("-cid", "--cluster_id", metavar="<cluster-id>", type=check_cid, default="",
4646
help="Cluster id is needed for '--ide', '--terminate_cluster' and '--update'. "
4747
"If not set, last created cluster's id is used")

bibigrid/core/utility/handler/cluster_ssh_handler.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import os
66

77
from bibigrid.core.actions import list_clusters
8-
from bibigrid.core.utility.statics.create_statics import KEY_FOLDER, KEY_NAME
8+
from bibigrid.core.utility.statics.create_statics import KEY_NAME
9+
from bibigrid.core.utility.paths.basic_path import KEY_FOLDER
910

1011

1112
def get_ssh_connection_info(cluster_id, master_provider, master_configuration, log):

bibigrid/core/utility/paths/basic_path.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,14 @@
99
# if the relative path from this file to resources is altered, the next line must be adapted or files will not be found.
1010
ROOT_PATH = Path(__file__).absolute().parents[4]
1111
RESOURCES_PATH = os.path.join(ROOT_PATH, RESOURCES)
12+
13+
STANDARD_CONFIG_PATH = "~/.config/bibigrid"
14+
CLUSTER_INFO = "cluster_info"
15+
CONFIG_FOLDER = os.path.expanduser(STANDARD_CONFIG_PATH)
16+
CLUSTER_INFO_FOLDER = os.path.join(CONFIG_FOLDER, CLUSTER_INFO)
17+
18+
KEY_FOLDER = os.path.join(CONFIG_FOLDER, "keys/")
19+
20+
CLUSTER_MEMORY_FOLDER = KEY_FOLDER
21+
CLUSTER_MEMORY_FILE = ".bibigrid.mem"
22+
CLUSTER_MEMORY_PATH = os.path.join(CONFIG_FOLDER, CLUSTER_MEMORY_FILE)

bibigrid/core/utility/statics/create_statics.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
Containg static variables for create.py to avoid cyclic imports
33
"""
44

5-
import os
65
from functools import partial
76

87
from bibigrid.core.utility.paths import ansible_resources_path as a_rp
@@ -32,12 +31,7 @@ def get_identifier(identifier, cluster_id, additional=""):
3231
VPNGTW_IDENTIFIER = partial(get_identifier, identifier="vpngtw")
3332

3433
KEY_PREFIX = "tempKey_bibi"
35-
CONFIG_FOLDER = os.path.expanduser("~/.config/bibigrid/")
36-
KEY_FOLDER = os.path.join(CONFIG_FOLDER, "keys/")
3734
AC_NAME = "ac" + SEPARATOR + "{cluster_id}"
3835
KEY_NAME = KEY_PREFIX + SEPARATOR + "{cluster_id}"
39-
CLUSTER_MEMORY_FOLDER = KEY_FOLDER
40-
CLUSTER_MEMORY_FILE = ".bibigrid.mem"
41-
CLUSTER_MEMORY_PATH = os.path.join(CONFIG_FOLDER, CLUSTER_MEMORY_FILE)
4236
DEFAULT_SECURITY_GROUP_NAME = "default" + SEPARATOR + "{cluster_id}"
4337
WIREGUARD_SECURITY_GROUP_NAME = "wireguard" + SEPARATOR + "{cluster_id}"

bibigrid/core/utility/validate_schema.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
Optional('sshPublicKeyFiles'): [str], Optional('sshTimeout'): int,
5050
Optional('cloudScheduling'): {Optional('sshTimeout'): int}, Optional('autoMount'): bool,
5151
Optional('nfsShares'): [str],
52-
Optional('userRoles'): [{'hosts': [str], 'roles': [{'name': str, Optional('tags'): [str]}], Optional('varsFiles'): [str]}],
52+
Optional('userRoles'): [
53+
{'hosts': [str], 'roles': [{'name': str, Optional('tags'): [str]}], Optional('varsFiles'): [str]}],
5354
Optional('localFS'): bool, Optional('localDNSlookup'): bool, Optional('slurm'): bool,
5455
Optional('slurmConf'): {Optional('db'): str, Optional('db_user'): str, Optional('db_password'): str,
5556
Optional('munge_key'): str, Optional('elastic_scheduling'): {Optional('SuspendTime'): int,

0 commit comments

Comments
 (0)