Compare commits
18 Commits
main
...
clore-rent
Author | SHA1 | Date |
---|---|---|
|
87a7265edc | |
|
b109094683 | |
|
f5f247dcd8 | |
|
9e684062f9 | |
|
9ccd0aba8a | |
|
7ff426f9ba | |
|
07134d26d7 | |
|
a60adedafd | |
|
2263d293c8 | |
|
4953ffe965 | |
|
de683b989e | |
|
cfba5d729d | |
|
9a36cf99bf | |
|
90a76735e2 | |
|
b74bb34f40 | |
|
b3502c8778 | |
|
92dac6755b | |
|
6fc2ac9b93 |
|
@ -11,6 +11,7 @@ import re
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import traceback
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
import subprocess
|
import subprocess
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
@ -20,22 +21,34 @@ class logger:
|
||||||
GREEN = '\033[92m'
|
GREEN = '\033[92m'
|
||||||
BLUE = '\033[94m'
|
BLUE = '\033[94m'
|
||||||
RESET = '\033[0m'
|
RESET = '\033[0m'
|
||||||
|
LOG_FILE = '/opt/clore-hosting/clore_onboarding.log'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_current_time():
|
def _get_current_time():
|
||||||
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _log_to_file(level, message):
|
||||||
|
try:
|
||||||
|
with open(logger.LOG_FILE, 'a') as f:
|
||||||
|
f.write(f"{logger._get_current_time()} | {level} | {message}\n")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def error(message):
|
def error(message):
|
||||||
print(f"{logger.RED}{logger._get_current_time()} | ERROR | {message}{logger.RESET}")
|
print(f"{logger.RED}{logger._get_current_time()} | ERROR | {message}{logger.RESET}")
|
||||||
|
logger._log_to_file("ERROR", message)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def success(message):
|
def success(message):
|
||||||
print(f"{logger.GREEN}{logger._get_current_time()} | SUCCESS | {message}{logger.RESET}")
|
print(f"{logger.GREEN}{logger._get_current_time()} | SUCCESS | {message}{logger.RESET}")
|
||||||
|
logger._log_to_file("SUCCESS", message)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def info(message):
|
def info(message):
|
||||||
print(f"{logger.BLUE}{logger._get_current_time()} | INFO | {message}{logger.RESET}")
|
print(f"{logger.BLUE}{logger._get_current_time()} | INFO | {message}{logger.RESET}")
|
||||||
|
logger._log_to_file("INFO", message)
|
||||||
|
|
||||||
if os.geteuid() != 0:
|
if os.geteuid() != 0:
|
||||||
logger.error("This script must be run as root!")
|
logger.error("This script must be run as root!")
|
||||||
|
@ -89,7 +102,7 @@ def validate_clore_config(clore_config):
|
||||||
1 <= value["on_demand_multiplier"] <= 50 and 1 <= value["spot_multiplier"] <= 50
|
1 <= value["on_demand_multiplier"] <= 50 and 1 <= value["spot_multiplier"] <= 50
|
||||||
|
|
||||||
def is_valid_mrl(value):
|
def is_valid_mrl(value):
|
||||||
return isinstance(value, int) and 6 <= value <= 1440
|
return isinstance(value, int) and 6 <= value <= 3000
|
||||||
|
|
||||||
def is_valid_keep_params(value):
|
def is_valid_keep_params(value):
|
||||||
return isinstance(value, bool)
|
return isinstance(value, bool)
|
||||||
|
@ -98,9 +111,9 @@ def validate_clore_config(clore_config):
|
||||||
required_keys = {"on_demand_bitcoin", "on_demand_clore", "spot_bitcoin", "spot_clore"}
|
required_keys = {"on_demand_bitcoin", "on_demand_clore", "spot_bitcoin", "spot_clore"}
|
||||||
if required_keys.issubset(clore_config):
|
if required_keys.issubset(clore_config):
|
||||||
return 0.000001 <= clore_config["on_demand_bitcoin"] <= 0.005 and \
|
return 0.000001 <= clore_config["on_demand_bitcoin"] <= 0.005 and \
|
||||||
0.1 <= clore_config["on_demand_clore"] <= 5000 and \
|
0.1 <= clore_config["on_demand_clore"] <= 10000 and \
|
||||||
0.000001 <= clore_config["spot_bitcoin"] <= 0.005 and \
|
0.000001 <= clore_config["spot_bitcoin"] <= 0.005 and \
|
||||||
0.1 <= clore_config["spot_clore"] <= 5000
|
0.1 <= clore_config["spot_clore"] <= 10000
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_valid_usd_pricing(autoprice):
|
def is_valid_usd_pricing(autoprice):
|
||||||
|
@ -126,7 +139,7 @@ def validate_clore_config(clore_config):
|
||||||
errors.append("multipliers are not following spec")
|
errors.append("multipliers are not following spec")
|
||||||
|
|
||||||
if "mrl" not in clore_config or not is_valid_mrl(clore_config["mrl"]):
|
if "mrl" not in clore_config or not is_valid_mrl(clore_config["mrl"]):
|
||||||
errors.append("mrl is mandatory and must be an integer in range 6-1440")
|
errors.append("mrl is mandatory and must be an integer in range 6-3000")
|
||||||
|
|
||||||
if "keep_params" in clore_config and not is_valid_keep_params(clore_config["keep_params"]):
|
if "keep_params" in clore_config and not is_valid_keep_params(clore_config["keep_params"]):
|
||||||
errors.append("keep_params must be a boolean value")
|
errors.append("keep_params must be a boolean value")
|
||||||
|
@ -257,6 +270,20 @@ async def hive_load_configs(default_power_limits, static_config):
|
||||||
clore_config = possible_clore_config
|
clore_config = possible_clore_config
|
||||||
elif key == "CUSTOM_MINER" and value == "clore":
|
elif key == "CUSTOM_MINER" and value == "clore":
|
||||||
clore_miner_present = True
|
clore_miner_present = True
|
||||||
|
elif key == "CLORE_RENTALS_TOKEN":
|
||||||
|
possible_clore_config = base64_string_to_json(value)
|
||||||
|
if possible_clore_config:
|
||||||
|
clore_config = possible_clore_config
|
||||||
|
elif key == "META":
|
||||||
|
try:
|
||||||
|
meta_value = json.loads(value)
|
||||||
|
if (isinstance(meta_value, dict) and
|
||||||
|
"clore-rentals" in meta_value and
|
||||||
|
isinstance(meta_value["clore-rentals"], dict) and
|
||||||
|
meta_value["clore-rentals"].get("coin") == "CLORE-Rentals"):
|
||||||
|
clore_miner_present = True
|
||||||
|
except (json.JSONDecodeError, TypeError, KeyError) as e:
|
||||||
|
pass
|
||||||
|
|
||||||
if (not clore_miner_present or not clore_config) and parsed_static_config:
|
if (not clore_miner_present or not clore_config) and parsed_static_config:
|
||||||
clore_miner_present = True
|
clore_miner_present = True
|
||||||
|
@ -368,7 +395,13 @@ async def post_request(url, body, headers=None, timeout=15):
|
||||||
return status_code, response_data
|
return status_code, response_data
|
||||||
|
|
||||||
except (http.client.HTTPException, TimeoutError) as e:
|
except (http.client.HTTPException, TimeoutError) as e:
|
||||||
print(f"Request failed: {e}")
|
logger.error(f"Request failed: {e}")
|
||||||
|
return None, None
|
||||||
|
except socket.gaierror as e:
|
||||||
|
logger.error(f"DNS resolution failed for {url}: {e}")
|
||||||
|
return None, None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Unexpected error in post_request: {e}")
|
||||||
return None, None
|
return None, None
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
@ -425,8 +458,11 @@ if args.write_linux_config:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
async def main(machine_specs):
|
async def main(machine_specs):
|
||||||
|
logger.info("Started onboarding")
|
||||||
global next_retry_reached_server_limit
|
global next_retry_reached_server_limit
|
||||||
last_used_config = None
|
last_used_config = None
|
||||||
|
logger.info("logger.info(last_used_config) 1")
|
||||||
|
logger.info(last_used_config)
|
||||||
ever_pending_creation = False
|
ever_pending_creation = False
|
||||||
machine_id = get_machine_id()
|
machine_id = get_machine_id()
|
||||||
|
|
||||||
|
@ -440,9 +476,13 @@ async def main(machine_specs):
|
||||||
logger.error("Can't load default power limits of nVidia GPU(s)")
|
logger.error("Can't load default power limits of nVidia GPU(s)")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
logger.info("logger.info(last_used_config) 2")
|
||||||
|
logger.info(last_used_config)
|
||||||
|
|
||||||
oc_config = {}
|
oc_config = {}
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
logger.info("Looping")
|
||||||
if args.mode == "linux":
|
if args.mode == "linux":
|
||||||
clore_config = await async_read_file(clore_conf_path)
|
clore_config = await async_read_file(clore_conf_path)
|
||||||
clore_config = json.loads(clore_config)
|
clore_config = json.loads(clore_config)
|
||||||
|
@ -452,7 +492,10 @@ async def main(machine_specs):
|
||||||
machine_name, clore_config, oc_config = await hive_load_configs(default_power_limits, static_clore_config)
|
machine_name, clore_config, oc_config = await hive_load_configs(default_power_limits, static_clore_config)
|
||||||
#print(f"Machine Name: {machine_name}")
|
#print(f"Machine Name: {machine_name}")
|
||||||
|
|
||||||
|
logger.info(args.mode)
|
||||||
|
|
||||||
config_validation = validate_clore_config(clore_config)
|
config_validation = validate_clore_config(clore_config)
|
||||||
|
|
||||||
if config_validation == "Validation successful":
|
if config_validation == "Validation successful":
|
||||||
if "save_config" in clore_config and args.mode == "hive":
|
if "save_config" in clore_config and args.mode == "hive":
|
||||||
verify_or_update_file(clore_conf_path, json.dumps(clore_config))
|
verify_or_update_file(clore_conf_path, json.dumps(clore_config))
|
||||||
|
@ -461,6 +504,12 @@ async def main(machine_specs):
|
||||||
clore_config["clear_oc_override"] = True
|
clore_config["clear_oc_override"] = True
|
||||||
else:
|
else:
|
||||||
clore_config["stock_oc_override"] = oc_config
|
clore_config["stock_oc_override"] = oc_config
|
||||||
|
|
||||||
|
logger.info("Is config different")
|
||||||
|
logger.info(clore_config != last_used_config)
|
||||||
|
logger.info(clore_config)
|
||||||
|
logger.info(last_used_config)
|
||||||
|
|
||||||
if clore_config != last_used_config or (time.time() > next_retry_reached_server_limit and next_retry_reached_server_limit > 0):
|
if clore_config != last_used_config or (time.time() > next_retry_reached_server_limit and next_retry_reached_server_limit > 0):
|
||||||
last_used_config = clore_config.copy()
|
last_used_config = clore_config.copy()
|
||||||
if type(clore_config) == dict and "hostname_override" in clore_config:
|
if type(clore_config) == dict and "hostname_override" in clore_config:
|
||||||
|
@ -490,7 +539,7 @@ async def main(machine_specs):
|
||||||
await asyncio.sleep(60 if ever_pending_creation else 10)
|
await asyncio.sleep(60 if ever_pending_creation else 10)
|
||||||
ever_pending_creation = True
|
ever_pending_creation = True
|
||||||
last_used_config = None
|
last_used_config = None
|
||||||
elif "init_communication_token" in response_data and "private_communication_token":
|
elif "init_communication_token" in response_data and "private_communication_token" in response_data:
|
||||||
clore_hosting_sw_auth_str = f"{response_data['init_communication_token']}:{response_data['private_communication_token']}"
|
clore_hosting_sw_auth_str = f"{response_data['init_communication_token']}:{response_data['private_communication_token']}"
|
||||||
was_ok = verify_or_update_file(args.auth_file, clore_hosting_sw_auth_str)
|
was_ok = verify_or_update_file(args.auth_file, clore_hosting_sw_auth_str)
|
||||||
if was_ok:
|
if was_ok:
|
||||||
|
@ -507,9 +556,13 @@ async def main(machine_specs):
|
||||||
logger.error(f"Could not parse config - {' | '.join(config_validation)}")
|
logger.error(f"Could not parse config - {' | '.join(config_validation)}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger.error(f"Exception: {e}")
|
||||||
|
logger.error(f"Traceback: {traceback.format_exc()}")
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
logger.info("logger.info(last_used_config) 3")
|
||||||
|
logger.info(last_used_config)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
machine_specs = specs.get(benchmark_disk=True, mock=args.mock)
|
machine_specs = specs.get(benchmark_disk=True, mock=args.mock)
|
||||||
asyncio.run(main(machine_specs))
|
asyncio.run(main(machine_specs))
|
Loading…
Reference in New Issue