You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
7.6 KiB
Plaintext

package main
import "core:encoding/ini"
import "core:encoding/json"
import "core:fmt"
import "core:log"
import "core:mem"
import "core:os"
import "core:strconv"
import "core:strings"
import "core:time"
import "libs/http"
import "libs/http/client"
import "libs/sysinfo"
CONFIG_FILE_PATH :: "./config.ini"
PC: Program_Config = {}
api_request_get :: proc(endpoint: string) -> (body: client.Body_Type, allocation: bool, ok: bool) {
request: client.Request
client.request_init(&request, .Get)
defer client.request_destroy(&request)
response, err := client.request(&request, endpoint)
if err != nil {
return nil, false, false
}
defer client.response_destroy(&response)
body_err: client.Body_Error
body, allocation, body_err = client.response_body(&response)
if body_err != nil {
return nil, false, false
}
return body, allocation, true
}
// api_request_post :: proc(endpoint: string, post_body: any) -> (body: client.Body_Type, allocation: bool, ok: bool) {
// request: client.Request
// client.requset_init(&request, .Post)
// defer client.request_destroy(&request)
// if err := client.with_json(&request, post_body); err != nil do return nil, false, false
// response, err := client.request(&request, endpoint)
// if err != nil do return nil, false, false
// defer client.response_destroy(&response)
// }
// Returns the host ID, or if the host doesn't exist in
// LSM then it will return -1
get_host_id :: proc(hostname: string) -> (host_id: int, ok: bool) {
request: client.Request
client.request_init(&request, .Get)
defer client.request_destroy(&request)
endpoint := fmt.tprintf("%s/hosts/get_host_id_for_hostname/%s", PC.api_address, hostname)
response, err := client.request(&request, endpoint)
if err != nil {
return 0, false
}
defer client.response_destroy(&response)
body, allocation, body_err := client.response_body(&response)
if body_err != nil {
return 0, false
}
if response.status == .Not_Found && strings.contains(body.(client.Body_Plain), "record not found") {
return -1, true
} else if response.status != .OK {
return 0, false
}
host_id = strconv.atoi(body.(client.Body_Plain))
return host_id, true
}
get_cpus_for_host_from_id :: proc(host_id: int) -> (cpus: [dynamic]CPU, ok: bool) {
endpoint := fmt.tprintf("%s/cpus/get_cpus_by_host_id/%d", PC.api_address, host_id)
body, allocation, request_ok := api_request_get(endpoint)
if !request_ok {
return nil, false
}
defer client.body_destroy(body, allocation)
if body.(client.Body_Plain) == "[]" {
return cpus, true
}
body_data := transmute([]u8)body.(client.Body_Plain)
json_data, err := json.parse(body_data)
if err != .None {
return nil, false
}
defer json.destroy_value(json_data)
root := json_data.(json.Array)
for cpu, i in root {
resize(&cpus, len(cpus)+1)
cpu_object := cpu.(json.Object)
cpus[i].id = int(cpu_object["id"].(json.Float))
cpus[i].socket = int(cpu_object["socket"].(json.Float))
cpus[i].name = strings.clone(cpu_object["name"].(json.String))
}
return cpus, true
}
destroy_cpus :: proc(cpus: [dynamic]CPU) {
for cpu in cpus {
delete(cpu.name)
}
delete(cpus)
}
add_cpu_to_lsm :: proc(cpu_name: string, socket, cores: int, usage: f64, host_id: int) -> bool {
request: client.Request
client.request_init(&request, .Post)
defer client.request_destroy(&request)
post_body := Base_CPU{cpu_name, socket, cores, usage, host_id}
if err := client.with_json(&request, post_body); err != nil {
return false
}
response, err := client.request(&request, fmt.tprintf("%s/cpus/add_cpu_to_host", PC.api_address))
if err != nil {
log.fatal("failed to add host to api with the error: ", err)
os.exit(1)
}
defer client.response_destroy(&response)
log.debugf("got response status %v when attempting to add cpu to lsm", response.status)
if response.status != .Created {
return false
}
return true
}
_main :: proc() {
context.logger = log.create_console_logger(.Info)
defer log.destroy_console_logger(context.logger)
data, ok := os.read_entire_file_from_filename(CONFIG_FILE_PATH)
if !ok {
fmt.eprintln("Failed to open config file")
return
}
defer delete(data)
data_str := strings.to_lower(transmute(string)data, allocator=context.temp_allocator)
ini_config, err := ini.load_map_from_string(data_str, allocator=context.allocator)
if err != nil {
log.fatal("failed to read config file")
return
}
defer ini.delete_map(ini_config)
if _, ok := ini_config["log"]; ok {
if level, ok := ini_config["log"]["level"]; ok && level in Log_Level_Map {
log_level := strings.to_upper(level, context.temp_allocator)
log_level_ok: bool
PC.log_level, log_level_ok = Log_Level_Map[log_level]
} else {
log.info("log level has either been not specified in configuration file or an invalid level has been specified")
log.info("defaulting to info")
PC.log_level = log.Level.Info
}
}
context.logger.lowest_level = PC.log_level
if _, ok := ini_config["api"]; ok {
if api_address, ok := ini_config["api"]["address"]; ok {
PC.api_address = api_address
} else {
log.fatal("api address not specified in config file")
return
}
}
log.debug("program config:", PC)
PC.hostname, ok = sysinfo.get_hostname()
if !ok {
log.fatal("failed to get hostname")
return
}
defer delete(PC.hostname)
log.info("successfully got hostname")
PC.host_id, ok = get_host_id(PC.hostname)
if !ok {
log.fatal("failed to contact the lsm api and determine if host already exists in lsm")
return
}
if PC.host_id < 0 {
log.info("Host doesn't exist in LSM")
log.info("Adding host now")
request: client.Request
client.request_init(&request, .Post)
defer client.request_destroy(&request)
post_body := Base_Host{PC.hostname}
if err := client.with_json(&request, post_body); err != nil {
log.fatal("JSON error:", err)
// TODO: Handle this
}
response, err := client.request(&request, fmt.tprintf("%s/hosts/add_host", PC.api_address))
if err != nil {
log.fatal("failed to add host to LSM with the error: %s", err)
return
}
defer client.response_destroy(&response)
if response.status == .Created {
log.info("successfully added host to lsm")
PC.host_id, ok = get_host_id(PC.hostname)
if !ok {
log.fatal("failed to get host id, exiting")
return
}
} else {
log.fatal("failed to add host to LSM got status code:", response.status)
return
}
} else {
log.info("host found in lsm")
}
log.debug("host id", PC.host_id)
cpu_name, socket, cpu_name_and_socket_ok := sysinfo.get_cpu_name_and_socket_number()
if !cpu_name_and_socket_ok {
log.fatal("failed to get cpu name and socket")
return
}
log.debug("got cpu name and socket")
cores, cores_ok := sysinfo.get_numb_cpu_cores()
if !cores_ok {
log.fatal("failed to get number of cpu cores")
return
}
log.debug("got number of cpu cores")
log.debug("starting main loop")
for {
usage, usage_ok := sysinfo.get_cpu_usage_perc()
log.info("USAGE:", usage)
if !usage_ok {
log.fatal("failed to get cpu usage")
return
} else {
log.debug("successfully got cpu usage")
}
if ok := add_cpu_to_lsm(cpu_name, socket, cores, usage, PC.host_id); !ok {
log.error("failed to add cpu")
} else {
log.info("successfully added cpu to lsm")
}
time.sleep(1 * time.Second)
}
}
main :: proc() {
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
context.allocator = mem.tracking_allocator(&track)
_main()
for _, leak in track.allocation_map {
fmt.println(leak.location, "leaked", leak.size, "bytes")
}
for bad_free in track.bad_free_array {
fmt.println(bad_free.location, "allocation", bad_free.memory, "was freed badly")
}
}