func new_reg_resp_from_hashed(hr hashed_registry_response) (*registry_response, error) { h := md5.New() h.Write([]byte(hr.ResponseStr)) hash_expect := hex.EncodeToString(h.Sum(nil)) if hr.Hash != hash_expect { return nil, logging.SErrorf("hash doesn't match: (got)%s != (expected)%s", hr.Hash, hash_expect) } var resp registry_response err := json.Unmarshal([]byte(hr.ResponseStr), &resp) if err != nil { return nil, logging.SErrorf("failed to unmarshal RegistryResponse: %v", err) } return &resp, nil }
func new_hashed_reg_response_from_json(dump []byte) (*hashed_registry_response, error) { var hr hashed_registry_response err := json.Unmarshal(dump, &hr) if err != nil { logging.Errorf("dump: %s", string(dump)) return nil, logging.SErrorf("failed to unmarshal HashedRegistryResponse: %v", err) } return &hr, nil }
func WatchRuntimeConfFromEtcd(etcd_machines []string, etcd_path string, stop chan error) <-chan RespConfig { logging.Info("WatchRuntimeConfFromEtcd Started") var ( out = make(chan RespConfig, 1) sleep_duration = time.Second // sleep_duration = time.Second * 5 ) if stop == nil { panic("stop chan is nil") } go func() { var ( the_first_time = true watching = false chGetConf <-chan time.Time chWaching <-chan time.Time ) client := etcd.NewClient(etcd_machines) cached_conf, _ := LoadRuntimeConfFromPath(CONF_CACHE_PATH) watch_stop := make(chan bool, 0) loop: for { if watching == false && chGetConf == nil { if the_first_time == true { chGetConf = time.After(0) } else { chGetConf = time.After(sleep_duration) } } if watching == true && chWaching == nil { chWaching = time.After(sleep_duration) } select { case <-stop: logging.Info("stop watching etcd.") watch_stop <- true logging.Info("watching etcd stopped.") break loop case <-chGetConf: the_first_time = false chGetConf = nil tmp_conf, err := getRuntimeConfFromEtcd(client, etcd_path) if err != nil { if cached_conf != nil { // if failed to get config from etcd but we have a cached copy. then use // this cached version first. out <- RespConfig{cached_conf, nil} cached_conf = nil // cached copy only need to emit once. } else { out <- RespConfig{nil, logging.SErrorf("failed to getRuntimeConfFromEtcd: %v", err)} } } else { out <- RespConfig{tmp_conf, nil} watching = true } case <-chWaching: chWaching = nil logging.Infof("watching etcd remote config: %s, %s", etcd_machines, etcd_path) resp, err := client.Watch(etcd_path, 0, false, nil, watch_stop) if err != nil { logging.Errorf("watching etcd error: %v", err) break } r := bytes.NewReader([]byte(resp.Node.Value)) tmp_conf, err := ReadRuntimeConfig(r) if err != nil { logging.Errorf("watching etcd. changes detected but faild to parse config: %v", err) break } logging.Infof("a new config is comming") out <- RespConfig{tmp_conf, nil} } } }() return out }
func do_registry(reg_url string) (*registry_response, error) { logging.Debug("do_registry started") req, err := new_reg_request() if err != nil { return nil, logging.SError(err) } hReq, err := new_hashed_reg_request(req) if err != nil { return nil, logging.SError(err) } hResp, err := goreq.Request{ Method: "POST", Uri: reg_url, Body: hReq, Accept: "application/json", ContentType: "application/json", UserAgent: "hickwall", Timeout: 10 * time.Second, }.Do() if serr, ok := err.(*goreq.Error); ok { if serr.Timeout() { return nil, logging.SError(err) } return nil, logging.SErrorf("registry failed: %d", hResp.StatusCode) } defer hResp.Body.Close() if hResp.StatusCode != 200 { return nil, logging.SErrorf("status code != 200: %d", hResp.StatusCode) } body, err := ioutil.ReadAll(hResp.Body) if err != nil { return nil, logging.SErrorf("failed to read body %v", err) } resp, err := new_reg_response_from_json(body) if err != nil { return nil, logging.SError(err) } if resp.ErrorCode != 0 { if resp.ErrorCode == 1001 { logging.Warn("this agent already registried.") } else { return nil, logging.SErrorf("registry server give this error: %d, msg: %s", resp.ErrorCode, resp.ErrorMsg) } } if len(resp.EtcdMachines) <= 0 { return nil, logging.SError("EtcdMachines is empty") } for _, m := range resp.EtcdMachines { machine, err := url.Parse(m) if err != nil { return nil, logging.SErrorf("invalid etcd machine url: %s", err) } if machine.Scheme != "http" { return nil, logging.SErrorf("etcd machine url only support http : %s", m) } } if resp.EtcdConfigPath == "" { return nil, logging.SError("config path is empty") } if resp.RequestHash != hReq.Hash { return nil, logging.SErrorf("request hash and response hash mismatch: %s != (response)%s", hReq.Hash, resp.RequestHash) } resp.Request = req logging.Debug("do_registry finished") resp.Save() return resp, nil }