func HandleTriggerCustomEvent(e *tree_event.Event, api_cmd Command) { var ( out = &WriterCallback{BufferMaxSize: 1024} event_name = string(api_cmd.Data) err tree_lib.TreeError ev_data []byte ) err.From = tree_lib.FROM_TRIGGER_CUSTOM_EVENT out.OutCallback = func(data []byte, ended bool) { cb_cmd := api_cmd cb_cmd.Ended = ended cb_cmd.Data = data ev_data, err.Err = ffjson.Marshal(cb_cmd) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } SendCommandCallback(e, ev_data) } defer out.End() err = custom_event.Trigger(event_name, out) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } }
func HandleContainerCommand(ev *tree_event.Event, cmd Command) { var ( out = &WriterCallback{BufferMaxSize: 1024} docker_cmd = tree_docker.DockerCmd{} err tree_lib.TreeError ev_data []byte ) err.From = tree_lib.FROM_HANDLE_CONTAINER_COMMAND err.Err = ffjson.Unmarshal(cmd.Data, &docker_cmd) if !err.IsNull() { tree_log.Error(err.From, "unable to unmarshal command data as a docker command -> ", err.Error()) return } out.OutCallback = func(data []byte, ended bool) { cb_cmd := cmd cb_cmd.Ended = ended cb_cmd.Data = data ev_data, err.Err = ffjson.Marshal(cb_cmd) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } SendCommandCallback(ev, ev_data) } defer out.End() tree_docker.ContainerCommands(&docker_cmd, out) }
// Executing some commands using exec.Command functionality from Go in OS func HandleExecCommand(e *tree_event.Event, api_cmd Command) { var ( out = &WriterCallback{BufferMaxSize: 1024} cmd_str = string(api_cmd.Data) cmd_options = strings.Split(cmd_str, " ") cmd = exec.Command(cmd_options[0], cmd_options[1:]...) err tree_lib.TreeError ev_data []byte ) err.From = tree_lib.FROM_HANDLE_EXEC_COMMAND out.OutCallback = func(data []byte, ended bool) { cb_cmd := api_cmd cb_cmd.Ended = ended cb_cmd.Data = data ev_data, err.Err = ffjson.Marshal(cb_cmd) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } SendCommandCallback(e, ev_data) } defer out.End() cmd.Stdout = out cmd.Stderr = out err.Err = cmd.Run() if !err.IsNull() { tree_log.Error(err.From, err.Error()) } }
// Init API node for connection to targets func API_INIT(targets ...string) bool { var err tree_lib.TreeError err.From = tree_lib.FROM_API_INIT if len(targets) == 0 { tree_log.Error(err.From, "For running API client you need to specify target node(s) to connect") return false } for _, n := range targets { node_info.ChildsNodeInfo[n], err = tree_db.GetNodeInfo(n) if !err.IsNull() { tree_log.Error(err.From, fmt.Sprintf("Unable Getting target (%s) node info from Node database, ", n), err.Error()) return false } } rand.Seed(time.Now().UnixNano()) node_info.CurrentNodeInfo = node_info.NodeInfo{ Name: fmt.Sprintf("%s|%s", API_NAME_PREFIX, tree_lib.RandomString(10)), Childs: targets, // Getting next prime number based on Unix Timestamp nanoseconds and // TODO: Think about making this in a different way Value: tree_lib.NextPrimeNumber((1 * rand.Int63n(100)) + int64(100)), } node_info.CurrentNodeValue = big.NewInt(node_info.CurrentNodeInfo.Value) // Setting node values based on child list node_info.CalculateChildParentNodeValues() // After we have child information lets connect to them node_info.ChildsConnectionUpdate() return true }
func BuildCmdHandler(cmd *cobra.Command, args []string) { var ( silent, force, multiple bool err error ) silent, err = cmd.Flags().GetBool("silent") if err != nil { tree_log.Error(log_from_tree_build, "Unable to get 'silent' flag", err.Error()) return } force, err = cmd.Flags().GetBool("force") if err != nil { tree_log.Error(log_from_tree_build, "Unable to get 'force' flag", err.Error()) return } multiple, err = cmd.Flags().GetBool("multiple") if err != nil { tree_log.Error(log_from_tree_build, "Unable to get 'force' flag", err.Error()) return } generate_tmp_db_dir() // Adding fake flag for not duplicating code, and calling 'config' command cmd.Flags().String("out", tmp_db_dir, "") fmt.Println("Dumping Database file for transfer -> ", tmp_db_dir) CompileConfig(cmd, args) // After this step we have config in GLOBAL_CONFIG variable and db file for sending to nodes BuildTree(&GLOBAL_CONFIG, silent, force, multiple) }
func HandleDelete(cmd *cobra.Command, args []string) { var ( node string target []string tag []string group []string container string err tree_lib.TreeError ) err.From = tree_lib.FROM_HANDLE_DELETE node, err.Err = cmd.Flags().GetString("node") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } target, err.Err = cmd.Flags().GetStringSlice("target") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } container, err.Err = cmd.Flags().GetString("container") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } var ( docker_cmd = tree_docker.DockerCmd{} ) docker_cmd.Content = make(map[string]string) docker_cmd.Command = tree_docker.COMMAND_DOCKER_CONTAINER_DELETE docker_cmd.Content["container"] = container SendDockerCommand(docker_cmd, node, target, tag, group) }
func ListenParent() (err tree_lib.TreeError) { var ( addr *net.TCPAddr conn *net.TCPConn ) err.From = tree_lib.FROM_LISTEN_PARENT // If port is not set, setting it to default 8888 if node_info.CurrentNodeInfo.TreePort == 0 { node_info.CurrentNodeInfo.TreePort = 8888 } addr, err.Err = net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", node_info.CurrentNodeInfo.TreeIp, node_info.CurrentNodeInfo.TreePort)) if !err.IsNull() { tree_log.Error(err.From, "Network Listen function", err.Error()) return } listener, err.Err = net.ListenTCP("tcp", addr) if !err.IsNull() { tree_log.Error(err.From, "Network Listen function", err.Error()) return } for { conn, err.Err = listener.AcceptTCP() if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } // Handle Parent connection go handle_api_or_parent_connection(conn) } return }
func HandleNodeCommand(cmd *cobra.Command, args []string) { var ( name string err tree_lib.TreeError ) err.From = tree_lib.FROM_HANDLE_NODE_COMMAND name, err.Err = cmd.Flags().GetString("set-name") if !err.IsNull() { tree_log.Error(err.From, err.Error()) } // If we have set-name flag then we just setting current_node in database and exiting if len(name) > 0 { tree_db.Set(tree_db.DB_RANDOM, []byte("current_node"), []byte(name)) return } daemon := false daemon, err.Err = cmd.Flags().GetBool("daemon") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if daemon { cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("%s node > %s 2>&1 &", os.Args[0], tree_log.LogFile)) err.Err = cmd.Run() if !err.IsNull() { log.Fatal(err.Err) } return } name, err.Err = cmd.Flags().GetString("name") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if len(name) == 0 { current_node_byte, err := tree_db.Get(tree_db.DB_RANDOM, []byte("current_node")) if !err.IsNull() { tree_log.Error(err.From, "Getting current node name from Random database, ", err.Error()) return } if len(current_node_byte) == 0 { fmt.Println("Name is important for the first time run") return } } else { err = tree_node.SetCurrentNode(name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } } tree_node.Start() }
func HandleAddCustomEventHandlers(e *tree_event.Event, api_cmd Command) { var ( out = &WriterCallback{BufferMaxSize: 1024} handler_data map[string]interface{} err tree_lib.TreeError ev_data []byte ) err.From = tree_lib.FROM_ADD_CUSTOM_EVENT err.Err = ffjson.Unmarshal(api_cmd.Data, &handler_data) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } out.OutCallback = func(data []byte, ended bool) { cb_cmd := api_cmd cb_cmd.Ended = ended cb_cmd.Data = data ev_data, err.Err = ffjson.Marshal(cb_cmd) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } SendCommandCallback(e, ev_data) } defer out.End() event_name := handler_data["name"].(string) handles_interfaces := handler_data["handlers"].([]interface{}) var ( handles_interfaces_data []byte handlers []custom_event.Handler ) handles_interfaces_data, err.Err = ffjson.Marshal(handles_interfaces) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err.Err = ffjson.Unmarshal(handles_interfaces_data, &handlers) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = custom_event.ON(event_name, handlers...) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } }
func SendToConn(data []byte, conn *net.TCPConn, path *big.Int) { // making variable for combining send data var ( err tree_lib.TreeError path_len_data = make([]byte, 4) msg_len_data = make([]byte, 4) path_data = path.Bytes() path_len = uint32(len(path_data)) buf = bytes.Buffer{} ) err.From = tree_lib.FROM_SEND_TO_CONN binary.LittleEndian.PutUint32(path_len_data, path_len) binary.LittleEndian.PutUint32(msg_len_data, path_len+uint32(len(data))+uint32(4)) buf.Write(msg_len_data) buf.Write(path_len_data) buf.Write(path_data) buf.Write(data) if conn != nil { _, err.Err = conn.Write(buf.Bytes()) if !err.IsNull() { tree_log.Error(err.From, fmt.Sprintf("Error sending data to path [%s]", path.String()), err.Error()) } } buf.Reset() }
func SendDockerCommand(cmd tree_docker.DockerCmd, node string, target []string, tag []string, group []string) { var err tree_lib.TreeError if !tree_api.API_INIT(node) { fmt.Println("Unable to init api client") fmt.Println("Exiting ...") return } err.From = tree_lib.FROM_SEND_DOCKER_COMMAND var ( api_cmd = tree_api.Command{} wait = make(chan bool) ) api_cmd.ID = tree_lib.RandomString(20) api_cmd.Data, err.Err = ffjson.Marshal(cmd) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } api_cmd.CommandType = tree_api.COMMAND_CONTAINER tree_event.ON(tree_event.ON_CHILD_CONNECTED, func(ev *tree_event.Event) { path := &tree_graph.Path{From: node, Nodes: target, Groups: group, Tags: tag} tree_api.SendCommand(&api_cmd, path, func(e *tree_event.Event, c tree_api.Command) bool { fmt.Println(string(c.Data)) fmt.Println(c.Ended) if c.Ended { return false } return true }) wait <- true }) <-wait }
func HandleUpdateCommand(ev *tree_event.Event, cmd Command) { var ( data Command info node_info.NodeInfo err tree_lib.TreeError ) err.From = tree_lib.FROM_HANDLE_UPDATE_COMMAND err.Err = ffjson.Unmarshal(ev.Data, &data) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } err.Err = ffjson.Unmarshal(data.Data, &info) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } UpdateNodeChange(info) SendCommandCallback(ev, ev.Data) }
func RestoreFromConfigDump(cmd *cobra.Command, args []string) { var ( dump_file string err tree_lib.TreeError ) err.From = tree_lib.FROM_RESTORE_FROM_CONFIG_DUMP dump_file, err.Err = cmd.Flags().GetString("file") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = tree_db.LoadFromDumpPath(dump_file) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } }
func PathFiles(conf_type string, paths []string) ([]string, tree_lib.TreeError) { var ( err_r tree_lib.TreeError names []string FileNames func(path string) (err tree_lib.TreeError) ) err_r.From = tree_lib.FROM_PATH_FILES FileNames = func(path string) (err tree_lib.TreeError) { err.From = tree_lib.FROM_PATH_FILES files_in_dir, e := ioutil.ReadDir(path) err.Err = e if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } for _, a := range files_in_dir { if !a.IsDir() { if strings.Replace(filepath.Ext(a.Name())[0:], ".", "", 1) == conf_type { names = append(names, fmt.Sprintf("%s/%s", path, a.Name())) } } else { err = FileNames(fmt.Sprintf("%s/%s", path, a.Name())) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } } } return } for _, a := range paths { if string([]rune(a)[len(a)-1]) == "/" { a = a[:len(a)-1] } err_r = FileNames(a) if !err_r.IsNull() { tree_log.Error(err_r.From, err_r.Error()) return nil, err_r } } return names, err_r }
func SetParent(name string) bool { var err tree_lib.TreeError err.From = tree_lib.FROM_SET_PARENT node_info.ParentNodeInfo, err = tree_db.GetNodeInfo(name) if !err.IsNull() { tree_log.Error(err.From, "Getting parent node info from Node database, ", err.Error()) return false } return true }
func HandleList(cmd *cobra.Command, args []string) { var ( node string target []string tag []string group []string err tree_lib.TreeError ) err.From = tree_lib.FROM_HANDLE_LIST node, err.Err = cmd.Flags().GetString("node") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } target, err.Err = cmd.Flags().GetStringSlice("target") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } tag, err.Err = cmd.Flags().GetStringSlice("tag") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } group, err.Err = cmd.Flags().GetStringSlice("group") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } var ( docker_cmd = tree_docker.DockerCmd{} ) docker_cmd.Content = make(map[string]string) if cmd.Parent().Name() == "container" { docker_cmd.Command = tree_docker.COMMAND_DOCKER_CONTAINER_LIST } else { docker_cmd.Command = tree_docker.COMMAND_DOCKER_IMAGE_LIST } docker_cmd.Content["all"] = "yes" SendDockerCommand(docker_cmd, node, target, tag, group) }
func node_init() { // Getting current node name current_node_byte, err := tree_db.Get(tree_db.DB_RANDOM, []byte("current_node")) err.From = tree_lib.FROM_NODE_INIT if !err.IsNull() { tree_log.Error(err.From, "Getting current node name from Random database, ", err.Error()) return } current_node_name = string(current_node_byte) node_info.CurrentNodeInfo, err = tree_db.GetNodeInfo(current_node_name) if !err.IsNull() { tree_log.Error(err.From, "Getting current node info from Node database, ", err.Error()) return } // Setting current Node Value field from string to big.Int node_info.CurrentNodeValue = nil // Setting to nil for garbage collection node_info.CurrentNodeValue = big.NewInt(node_info.CurrentNodeInfo.Value) for _, child := range node_info.CurrentNodeInfo.Childs { node_info.ChildsNodeInfo[child], err = tree_db.GetNodeInfo(child) if !err.IsNull() { tree_log.Error(err.From, fmt.Sprintf("Getting child (%s) node info from Node database, ", child), err.Error()) return } } // Setting relations tree_db.SetRelations(current_node_name) node_info.ParentNodeInfo, err = tree_db.GetParentInfo(current_node_name) if !err.IsNull() { tree_log.Error(err.From, "Getting parent node info from Node database, ", err.Error()) return } // Setting node values based on child list node_info.CalculateChildParentNodeValues() }
func TriggerFromData(data []byte) { var ( e = new(Event) err tree_lib.TreeError ) err.From = tree_lib.FROM_TRIGGER_FROM_DATA err.Err = ffjson.Unmarshal(data, e) if !err.IsNull() { tree_log.Error(log_from_event, err.Error()) return } Trigger(e) }
func UpdateNodeChange(info node_info.NodeInfo) { var ( ev = &tree_event.Event{} err tree_lib.TreeError ) err.From = tree_lib.FROM_UPDATE_NODE_CHANGE ev.Data, err.Err = ffjson.Marshal(info) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } path := &tree_graph.Path{From: node_info.CurrentNodeInfo.Name, Nodes: []string{"*"}} ev.Name = tree_event.ON_UPDATE_NODE_INFO tree_event.Trigger(ev) tree_event.Emit(ev, path) }
func HandleImageDelete(cmd *cobra.Command, args []string) { var ( node string target []string tag []string group []string force bool image string err tree_lib.TreeError ) err.From = tree_lib.FROM_HANDLE_IMAGE_DELETE node, err.Err = cmd.Flags().GetString("node") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } target, err.Err = cmd.Flags().GetStringSlice("target") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } tag, err.Err = cmd.Flags().GetStringSlice("tag") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } group, err.Err = cmd.Flags().GetStringSlice("group") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } image, err.Err = cmd.Flags().GetString("image") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } force, err.Err = cmd.Flags().GetBool("force") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } var ( docker_cmd = tree_docker.DockerCmd{} ) docker_cmd.Content = make(map[string]string) docker_cmd.Command = tree_docker.COMMAND_DOCKER_IMAGE_DELETE docker_cmd.Content["image"] = image if force { docker_cmd.Content["force"] = "yes" } else { docker_cmd.Content["force"] = "no" } SendDockerCommand(docker_cmd, node, target, tag, group) }
func InitBalancers() { err := tree_db.ForEach(tree_db.DB_BALANCER, func(k []byte, v []byte) error { var err error bc := tree_balancer.BalancerConfig{Name: string(k)} err = ffjson.Unmarshal(v, &bc) if err != nil { return err } // TODO: Maybe we need to collect balancer services in MAP or Array _, err = tree_balancer.NewBalancerFromConfig(bc) return err }) err.From = tree_lib.FROM_INIT_BALANCER if !err.IsNull() { tree_log.Error(err.From, "Unable to Init Balancers", err.Error()) return } }
func SendCommandCallback(e *tree_event.Event, data []byte) (err tree_lib.TreeError) { cb_ev := &tree_event.Event{} path := &tree_graph.Path{} cb_ev.Name = tree_event.ON_API_COMMAND_CALLBACK cb_ev.Data = data path.Nodes = []string{e.From} path.From = node_info.CurrentNodeInfo.Name _, err = path.CalculatePathToApi(big.NewInt(e.FromApi)) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } // If it comes from API, then we need multiply also with API's negative value /*if e.FromApi != 0 { p.Mul(p, big.NewInt(e.FromApi)) p.Mul(p, big.NewInt(e.FromApi)) }*/ tree_event.Emit(cb_ev, path) return }
func CompileConfig(cmd *cobra.Command, args []string) { var ( files []string conf_type string out_file string paths []string files_in_path []string err tree_lib.TreeError ) err.From = tree_lib.FROM_COMPILE_CONFIG files, err.Err = cmd.Flags().GetStringSlice("files") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } conf_type, err.Err = cmd.Flags().GetString("type") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } out_file, err.Err = cmd.Flags().GetString("out") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if _, err.Err = os.Stat(out_file); err.Err == nil { err.Err = os.Remove(out_file) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } } paths, err.Err = cmd.Flags().GetStringSlice("path") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if len(paths) > 0 { files_in_path, err = PathFiles(conf_type, paths) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } for _, a := range files_in_path { files = append(files, a) } } if len(files) > 0 { err = ParseFiles(conf_type, files...) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } } DBFromConfig() err = tree_db.DumpDBPath(out_file) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } // Deleting database dir from console part err.Err = os.RemoveAll(tree_db.DB_DIR) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } }
func DBFromConfig() { var ( err tree_lib.TreeError prev_prime = int64(1) ) err.From = tree_lib.FROM_DB_FROM_CONFIG for n, nf := range GLOBAL_CONFIG.TreeNode { nf.Value = tree_lib.NextPrimeNumber(prev_prime) prev_prime = nf.Value err = tree_db.SetNodeInfo(n, nf) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } } // After having All nodes information now we can set related things for every node for n, _ := range GLOBAL_CONFIG.TreeNode { // Setting relations for every Node err = tree_db.SetRelations(n) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } // Setting Groups with node lists in Group database err = tree_db.AddNodeToHisGroups(n) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } // Setting Tags with node lists in Group database err = tree_db.AddNodeToHisTags(n) if !err.IsNull() { tree_log.Error(err.From, err.Error()) } } // Setting Balancers for b, b_conf := range GLOBAL_CONFIG.Balancer { var b_data []byte b_data, err.Err = ffjson.Marshal(b_conf) if !err.IsNull() { tree_log.Error(err.From, "Error encoding balancer config", b, " -> ", err.Error()) continue } err = tree_db.Set(tree_db.DB_BALANCER, []byte(b), b_data) if !err.IsNull() { tree_log.Error(err.From, "Error setting balancer config", b, " -> ", err.Error()) } } // Setting Registry for r, r_conf := range GLOBAL_CONFIG.Registry { var r_data []byte r_data, err.Err = ffjson.Marshal(r_conf) if !err.IsNull() { tree_log.Error(err.From, "Error encoding registry config", r, " -> ", err.Error()) continue } err = tree_db.Set(tree_db.DB_REGISTRY, []byte(r), r_data) if !err.IsNull() { tree_log.Error(err.From, "Error setting registry config", r, " -> ", err.Error()) } } }
func SendEventTriggerCommand(cmd *cobra.Command, args []string) { var ( event_name string err tree_lib.TreeError node string targets []string target_groups []string target_tags []string ) err.From = tree_lib.FROM_SEND_COMMAND node, err.Err = cmd.Flags().GetString("node") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } targets, err.Err = cmd.Flags().GetStringSlice("target") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } target_groups, err.Err = cmd.Flags().GetStringSlice("group") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } target_tags, err.Err = cmd.Flags().GetStringSlice("tag") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } event_name, err.Err = cmd.Flags().GetString("event") if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if !tree_api.API_INIT(node) { fmt.Println("Unable to init api client") fmt.Println("Exiting ...") return } var ( api_cmd = tree_api.Command{} wait_to_end = make(chan bool) ) api_cmd.Data = []byte(event_name) api_cmd.ID = tree_lib.RandomString(20) api_cmd.CommandType = tree_api.COMMAND_TRIGGER_EVENT tree_event.ON(tree_event.ON_CHILD_CONNECTED, func(ev *tree_event.Event) { path := &tree_graph.Path{From: node, Nodes: targets, Tags: target_tags, Groups: target_groups} tree_api.SendCommand(&api_cmd, path, func(e *tree_event.Event, c tree_api.Command) bool { fmt.Println(string(c.Data)) fmt.Println(c.Ended) // TODO: End coming faster than other messages FIX !!!! if c.Ended { return false } return true }) wait_to_end <- true }) <-wait_to_end }
func handle_api_or_parent_connection(conn *net.TCPConn) { defer conn.Close() // Connection should be closed, after return this function var ( err tree_lib.TreeError msg_data []byte info_data []byte conn_name string is_api = false conn_node_info node_info.NodeInfo api_val *big.Int ) err.From = tree_lib.FROM_HANDLE_API_OR_PARENT_CONNECTION // Making basic handshake to check the API validation // Connected Parent receiving name of the child(current node) and checking is it valid or not // if it is valid name then parent sending his name as an answer // otherwise it sending CLOSE_CONNECTION_MARK and closing connection info_data, err.Err = ffjson.Marshal(node_info.CurrentNodeInfo) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } _, err.Err = tree_lib.SendMessage(info_data, conn) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } info_data, err = tree_lib.ReadMessage(conn) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } conn_name = string(info_data) if conn_name == CLOSE_CONNECTION_MARK { tree_log.Info(err.From, "Connection closed by parent node. Bad tree network handshake ! ", "Parent Addr: ", conn.RemoteAddr().String()) return } err.Err = ffjson.Unmarshal(info_data, &conn_node_info) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if strings.Contains(conn_node_info.Name, tree_api.API_NAME_PREFIX) { api_val = big.NewInt(conn_node_info.Value) api_connections[api_val] = conn is_api = true } else { // TODO: Think about conn_node_info if we need to more checking for parent node info parentConnection = conn } if is_api { tree_event.TriggerWithData(tree_event.ON_API_CONNECTED, info_data) } else { tree_event.TriggerWithData(tree_event.ON_PARENT_CONNECTED, info_data) } // Listening parent messages for { msg_data, err = tree_lib.ReadMessage(conn) if !err.IsNull() { tree_log.Error(err.From, " reading data from -> ", conn_name, " ", err.Error()) break } // Handling message events handle_message(is_api, true, msg_data) } if is_api { api_connections[api_val] = nil delete(api_connections, api_val) tree_event.TriggerWithData(tree_event.ON_API_DISCONNECTED, info_data) } else { parentConnection = nil tree_event.TriggerWithData(tree_event.ON_PARENT_DISCONNECTED, info_data) } }
func init() { // This event will be triggered from Node, when API client will send some command to implement tree_event.ON(tree_event.ON_API_COMMAND, func(ev *tree_event.Event) { var err tree_lib.TreeError err.From = tree_lib.FROM_INIT cmd := Command{} err.Err = ffjson.Unmarshal(ev.Data, &cmd) if !err.IsNull() { tree_log.Error(err.From, "unable to unmarshal event data as a command -> ", err.Error()) return } switch cmd.CommandType { case COMMAND_EXEC: { HandleExecCommand(ev, cmd) } case COMMAND_LIST: { HandleListCommand(ev, cmd) } case COMMAND_UPDATE: { HandleUpdateCommand(ev, cmd) } case COMMAND_CONTAINER: { HandleContainerCommand(ev, cmd) } case COMMAND_ADD_CUSTOM_EVENT: { HandleAddCustomEventHandlers(ev, cmd) } case COMMAND_TRIGGER_EVENT: { HandleTriggerCustomEvent(ev, cmd) } } }) // This event will be triggered from API client when Node will give callback for specific commands tree_event.ON(tree_event.ON_API_COMMAND_CALLBACK, func(ev *tree_event.Event) { var err tree_lib.TreeError err.From = tree_lib.FROM_INIT cmd := Command{} err.Err = ffjson.Unmarshal(ev.Data, &cmd) if !err.IsNull() { tree_log.Error(err.From, "unable to unmarshal event data as a command -> ", err.Error()) return } if cb, ok := subscribed_command_callbacks[cmd.ID]; ok && cb.f != nil { if !cb.f(ev, cmd) { // TODO: Maybe we need mutex to lock deleting process delete(subscribed_command_callbacks, cmd.ID) if cb.c != nil { cb.c <- true // Ending wait chanel in send command } } } }) }
func ChildConnect(name string) (err tree_lib.TreeError) { var ( conn *net.TCPConn curr_data []byte ch_info_data []byte conn_node_info node_info.NodeInfo msg []byte ) err.From = tree_lib.FROM_CHILD_CONNECT conn, err = TcpConnect(node_info.ChildsNodeInfo[name].TreeIp, node_info.ChildsNodeInfo[name].TreePort) if !err.IsNull() { tree_log.Error(err.From, " child_connect -> ", name, " ", err.Error()) return } defer conn.Close() ch_info_data, err = tree_lib.ReadMessage(conn) if !err.IsNull() { tree_log.Error(err.From, " child handshake -> ", name, " ", err.Error()) return } err.Err = ffjson.Unmarshal(ch_info_data, &conn_node_info) if !err.IsNull() { tree_log.Error(err.From, " child handshake -> ", name, " ", err.Error()) return } // If name revieved from connection not same name as we have // Then we connected to wrong server, just returning // defer will close connection if conn_node_info.Name != name { tree_lib.SendMessage([]byte(CLOSE_CONNECTION_MARK), conn) return } curr_data, err.Err = ffjson.Marshal(node_info.CurrentNodeInfo) if !err.IsNull() { tree_log.Error(err.From, " child handshake -> ", name, " ", err.Error()) return } _, err.Err = tree_lib.SendMessage(curr_data, conn) if !err.IsNull() { tree_log.Error(err.From, " child handshake sending current info to -> ", name, " ", err.Error()) return } child_connections[name] = conn tree_event.TriggerWithData(tree_event.ON_CHILD_CONNECTED, ch_info_data) for { msg, err = tree_lib.ReadMessage(conn) if !err.IsNull() { tree_log.Error(err.From, " reading data from child -> ", name, " ", err.Error()) break } handle_message(false, false, msg) } child_connections[name] = nil delete(child_connections, name) tree_event.TriggerWithData(tree_event.ON_CHILD_DISCONNECTED, ch_info_data) return }
func init() { var err tree_lib.TreeError err.From = tree_lib.FROM_INIT tree_db, err.Err = bolt.Open(DB_DIR, 0600, nil) if !err.IsNull() { tree_log.Error(log_from_db, " unable to open database", err.Error()) tree_db = nil os.Exit(1) // Without database we can't keep and share configurations, so program should be exited } // creating Buckets in database tree_db.Update(func(tx *bolt.Tx) (err error) { // Setting databases for _, d := range [][]byte{DB_NODE, DB_BALANCER, DB_RANDOM, DB_GROUP, DB_TAG, DB_RELATIONS, DB_REGISTRY, DB_EVENT} { _, err = tx.CreateBucketIfNotExists(d) if err != nil { return err } } return nil }) // Handling node change event tree_event.ON(tree_event.ON_UPDATE_NODE_INFO, func(e *tree_event.Event) { var ( info node_info.NodeInfo ev_info node_info.NodeInfo names []string data []byte mark bool ) err.Err = ffjson.Unmarshal(e.Data, &ev_info) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } info, err = GetNodeInfo(ev_info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if len(info.Name) > 0 { err = DeleteNodeFromHisGroups(info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = DeleteNodeFromHisTags(info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } if len(ev_info.TreeIp) > 0 { info.TreeIp = ev_info.TreeIp mark = true } if ev_info.TreePort != -1 { info.TreePort = ev_info.TreePort mark = true } if len(ev_info.Childs[0]) > 0 { info.Childs = append(info.Childs, ev_info.Childs[0]) } if len(ev_info.Childs[1]) > 0 { if g, ok := tree_lib.ArrayContains(info.Childs, ev_info.Childs[1]); ok { info.Childs = info.Childs[:g+copy(info.Childs[g:], info.Childs[g+1:])] } } if len(ev_info.Groups[0]) > 0 { info.Groups = append(info.Groups, ev_info.Groups[0]) } if len(ev_info.Groups[1]) > 0 { if g, ok := tree_lib.ArrayContains(info.Groups, ev_info.Groups[1]); ok { info.Groups = info.Groups[:g+copy(info.Groups[g:], info.Groups[g+1:])] } } if len(ev_info.Tags[0]) > 0 { info.Tags = append(info.Tags, ev_info.Tags[0]) } if len(ev_info.Tags[1]) > 0 { if g, ok := tree_lib.ArrayContains(info.Tags, ev_info.Tags[1]); ok { info.Tags = info.Tags[:g+copy(info.Tags[g:], info.Tags[g+1:])] } } data, err.Err = ffjson.Marshal(info) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = Set(DB_NODE, []byte(ev_info.Name), data) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } names, err = ListNodeNames() if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = AddNodeToHisGroups(info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = AddNodeToHisTags(info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } for _, n := range names { err = SetRelations(n) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } } if node_info.CurrentNodeInfo.Name == ev_info.Name && mark { var e1 tree_event.Event e1.Name = tree_event.ON_RESTART_NODE tree_event.Trigger(&e1) } } else { err = Set(DB_NODE, []byte(ev_info.Name), e.Data) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } names, err = ListNodeNames() if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = AddNodeToHisGroups(ev_info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err = AddNodeToHisTags(ev_info.Name) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } for _, n := range names { err = SetRelations(n) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } } if node_info.CurrentNodeInfo.Name == ev_info.Name { var e1 *tree_event.Event e1.Name = tree_event.ON_RESTART_NODE tree_event.Trigger(e1) } } }) // Closing database before program will be exited // Just in case if program exiting force or we don't want to make dead lock tree_event.ON(tree_event.ON_PROGRAM_EXIT, func(e *tree_event.Event) { CloseDB() }) }
func HandleListCommand(ev *tree_event.Event, cmd Command) { var ( info = make(map[string]node_info.NodeInfo) data []byte ev_data Command nodes []string nodes_in_group []string nodes_in_tag []string err tree_lib.TreeError infos Info ) err.From = tree_lib.FROM_HANDLE_LIST_COMMAND err.Err = ffjson.Unmarshal(ev.Data, &ev_data) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } err.Err = ffjson.Unmarshal(ev_data.Data, &infos) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } nodes = infos.Target for _, g := range infos.Group { nodes_in_group, err = tree_db.GetGroupNodes(g) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } for _, n := range nodes_in_group { nodes = append(nodes, n) } } for _, t := range infos.Tag { nodes_in_tag, err = tree_db.GetNodesByTagName(t) if !err.IsNull() { tree_log.Error(err.From, "getting Tags", err.Error()) return } for _, n := range nodes_in_tag { nodes = append(nodes, n) } } for _, n := range nodes { info[n], err = tree_db.GetNodeInfo(n) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } } cb_cmd := cmd cb_cmd.Data, err.Err = ffjson.Marshal(info) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } data, err.Err = ffjson.Marshal(cb_cmd) if !err.IsNull() { tree_log.Error(err.From, err.Error()) return } SendCommandCallback(ev, data) }