diff --git a/core/logs/alils/config.go b/core/logs/alils/config.go index 558db6a8..0b1d4256 100755 --- a/core/logs/alils/config.go +++ b/core/logs/alils/config.go @@ -1,7 +1,7 @@ package alils const ( - version = "0.5.0" // SDK version + version = "0.6.0" // SDK version signatureMethod = "hmac-sha1" // Signature method // OffsetNewest is the log head offset, i.e. the offset that will be diff --git a/core/logs/alils/log_project.go b/core/logs/alils/log_project.go index 700b50c7..91d08938 100755 --- a/core/logs/alils/log_project.go +++ b/core/logs/alils/log_project.go @@ -39,33 +39,62 @@ func NewLogProject(name, endpoint, AccessKeyID, accessKeySecret string) (p *LogP return p, nil } -// ListLogStore returns all logstore names of project p. -func (p *LogProject) ListLogStore() (storeNames []string, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - uri := "/logstores" - r, err := request(p, "GET", uri, h, nil) +// handleResponse is a helper function to process HTTP response and handle common error cases +// Returns response body as []byte and error if any +func handleResponse(r *http.Response, actionDesc string) ([]byte, error) { + body, err := io.ReadAll(r.Body) if err != nil { - return - } - - buf, err := io.ReadAll(r.Body) - if err != nil { - return + return nil, err } if r.StatusCode != http.StatusOK { errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) + err = json.Unmarshal(body, errMsg) if err != nil { - err = fmt.Errorf("failed to list logstore") + err = fmt.Errorf("failed to %s", actionDesc) dump, _ := httputil.DumpResponse(r, true) fmt.Printf("%s\n", dump) - return + return nil, err } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) + return nil, fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) + } + + return body, nil +} + +// sendRequest is a helper function to send HTTP request with specified method, uri, headers and body +// Returns response body as []byte and error if any +func (p *LogProject) sendRequest(method, uri string, headers map[string]string, body []byte) ([]byte, error) { + r, err := request(p, method, uri, headers, body) + if err != nil { + return nil, err + } + + return handleResponse(r, "process request "+method+" "+uri) +} + +// createStandardHeaders creates a map with standard headers for requests +func createStandardHeaders(bodyLen int) map[string]string { + if bodyLen <= 0 { + return map[string]string{ + "x-log-bodyrawsize": "0", + } + } + + return map[string]string{ + "x-log-bodyrawsize": fmt.Sprintf("%v", bodyLen), + "Content-Type": "application/json", + "Accept-Encoding": "deflate", // TODO: support lz4 + } +} + +// ListLogStore returns all logstore names of project p. +func (p *LogProject) ListLogStore() (storeNames []string, err error) { + h := createStandardHeaders(0) + uri := "/logstores" + + buf, err := p.sendRequest("GET", uri, h, nil) + if err != nil { return } @@ -81,39 +110,18 @@ func (p *LogProject) ListLogStore() (storeNames []string, err error) { } storeNames = body.LogStores - return } // GetLogStore returns logstore according by logstore name. func (p *LogProject) GetLogStore(name string) (s *LogStore, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) - r, err := request(p, "GET", "/logstores/"+name, h, nil) + buf, err := p.sendRequest("GET", "/logstores/"+name, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to get logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - s = &LogStore{} err = json.Unmarshal(buf, s) if err != nil { @@ -145,66 +153,15 @@ func (p *LogProject) CreateLogStore(name string, ttl, shardCnt int) (err error) return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "POST", "/logstores", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to create logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("POST", "/logstores", h, body) return } // DeleteLogStore deletes a logstore according by logstore name. func (p *LogProject) DeleteLogStore(name string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - r, err := request(p, "DELETE", "/logstores/"+name, h, nil) - if err != nil { - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + h := createStandardHeaders(0) + _, err = p.sendRequest("DELETE", "/logstores/"+name, h, nil) return } @@ -228,73 +185,26 @@ func (p *LogProject) UpdateLogStore(name string, ttl, shardCnt int) (err error) return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "PUT", "/logstores", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("PUT", "/logstores", h, body) return } // ListMachineGroup returns machine group name list and the total number of machine groups. // The offset starts from 0 and the size is the max number of machine groups could be returned. func (p *LogProject) ListMachineGroup(offset, size int) (m []string, total int, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) if size <= 0 { size = 500 } uri := fmt.Sprintf("/machinegroups?offset=%v&size=%v", offset, size) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to list machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Body struct { MachineGroups []string Count int @@ -309,39 +219,18 @@ func (p *LogProject) ListMachineGroup(offset, size int) (m []string, total int, m = body.MachineGroups total = body.Total - return } // GetMachineGroup retruns machine group according by machine group name. func (p *LogProject) GetMachineGroup(name string) (m *MachineGroup, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) - r, err := request(p, "GET", "/machinegroups/"+name, h, nil) + buf, err := p.sendRequest("GET", "/machinegroups/"+name, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to get machine group:%v", name) - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - m = &MachineGroup{} err = json.Unmarshal(buf, m) if err != nil { @@ -358,35 +247,8 @@ func (p *LogProject) CreateMachineGroup(m *MachineGroup) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "POST", "/machinegroups", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to create machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("POST", "/machinegroups", h, body) return } @@ -397,104 +259,33 @@ func (p *LogProject) UpdateMachineGroup(m *MachineGroup) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "PUT", "/machinegroups/"+m.Name, h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("PUT", "/machinegroups/"+m.Name, h, body) return } // DeleteMachineGroup deletes machine group according machine group name. func (p *LogProject) DeleteMachineGroup(name string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - r, err := request(p, "DELETE", "/machinegroups/"+name, h, nil) - if err != nil { - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + h := createStandardHeaders(0) + _, err = p.sendRequest("DELETE", "/machinegroups/"+name, h, nil) return } // ListConfig returns config names list and the total number of configs. // The offset starts from 0 and the size is the max number of configs could be returned. func (p *LogProject) ListConfig(offset, size int) (cfgNames []string, total int, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) if size <= 0 { size = 100 } uri := fmt.Sprintf("/configs?offset=%v&size=%v", offset, size) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Body struct { Total int Configs []string @@ -513,33 +304,13 @@ func (p *LogProject) ListConfig(offset, size int) (cfgNames []string, total int, // GetConfig returns config according by config name. func (p *LogProject) GetConfig(name string) (c *LogConfig, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) - r, err := request(p, "GET", "/configs/"+name, h, nil) + buf, err := p.sendRequest("GET", "/configs/"+name, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - c = &LogConfig{} err = json.Unmarshal(buf, c) if err != nil { @@ -556,35 +327,8 @@ func (p *LogProject) UpdateConfig(c *LogConfig) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "PUT", "/configs/"+c.Name, h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("PUT", "/configs/"+c.Name, h, body) return } @@ -595,99 +339,28 @@ func (p *LogProject) CreateConfig(c *LogConfig) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "POST", "/configs", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("POST", "/configs", h, body) return } // DeleteConfig deletes a config according by config name. func (p *LogProject) DeleteConfig(name string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - r, err := request(p, "DELETE", "/configs/"+name, h, nil) - if err != nil { - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + h := createStandardHeaders(0) + _, err = p.sendRequest("DELETE", "/configs/"+name, h, nil) return } // GetAppliedMachineGroups returns applied machine group names list according config name. func (p *LogProject) GetAppliedMachineGroups(confName string) (groupNames []string, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/configs/%v/machinegroups", confName) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to get applied machine groups") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Body struct { Count int Machinegroups []string @@ -705,34 +378,14 @@ func (p *LogProject) GetAppliedMachineGroups(confName string) (groupNames []stri // GetAppliedConfigs returns applied config names list according machine group name groupName. func (p *LogProject) GetAppliedConfigs(groupName string) (confNames []string, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/machinegroups/%v/configs", groupName) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to applied configs") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Cfg struct { Count int `json:"count"` Configs []string `json:"configs"` @@ -750,64 +403,18 @@ func (p *LogProject) GetAppliedConfigs(groupName string) (confNames []string, er // ApplyConfigToMachineGroup applies config to machine group. func (p *LogProject) ApplyConfigToMachineGroup(confName, groupName string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName) - r, err := request(p, "PUT", uri, h, nil) - if err != nil { - return - } - - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to apply config to machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + _, err = p.sendRequest("PUT", uri, h, nil) return } // RemoveConfigFromMachineGroup removes config from machine group. func (p *LogProject) RemoveConfigFromMachineGroup(confName, groupName string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName) - r, err := request(p, "DELETE", uri, h, nil) - if err != nil { - return - } - - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to remove config from machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + _, err = p.sendRequest("DELETE", uri, h, nil) return } diff --git a/core/logs/alils/log_store.go b/core/logs/alils/log_store.go index e699b832..ac19b6ed 100755 --- a/core/logs/alils/log_store.go +++ b/core/logs/alils/log_store.go @@ -32,7 +32,7 @@ type Shard struct { // ListShards returns shard id list of this logstore. func (s *LogStore) ListShards() (shardIDs []int, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", } uri := fmt.Sprintf("/logstores/%v/shards", s.Name) @@ -87,8 +87,8 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) { } h := map[string]string{ - "x-sls-compresstype": "lz4", - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), + "x-log-compresstype": "lz4", + "x-log-bodyrawsize": fmt.Sprintf("%v", len(body)), "Content-Type": "application/x-protobuf", } @@ -123,7 +123,7 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) { // For more detail please read: http://gitlab.alibaba-inc.com/sls/doc/blob/master/api/shard.md#logstore func (s *LogStore) GetCursor(shardID int, from string) (cursor string, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", } uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v", @@ -172,7 +172,7 @@ func (s *LogStore) GetLogsBytes(shardID int, cursor string, logGroupMaxCount int) (out []byte, nextCursor string, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", "Accept": "application/x-protobuf", "Accept-Encoding": "lz4", } @@ -203,9 +203,9 @@ func (s *LogStore) GetLogsBytes(shardID int, cursor string, return } - v, ok := r.Header["X-Sls-Compresstype"] + v, ok := r.Header["X-Log-Compresstype"] if !ok || len(v) == 0 { - err = fmt.Errorf("can't find 'x-sls-compresstype' header") + err = fmt.Errorf("can't find 'x-log-compresstype' header") return } if v[0] != "lz4" { @@ -213,16 +213,16 @@ func (s *LogStore) GetLogsBytes(shardID int, cursor string, return } - v, ok = r.Header["X-Sls-Cursor"] + v, ok = r.Header["X-Log-Cursor"] if !ok || len(v) == 0 { - err = fmt.Errorf("can't find 'x-sls-cursor' header") + err = fmt.Errorf("can't find 'x-log-cursor' header") return } nextCursor = v[0] - v, ok = r.Header["X-Sls-Bodyrawsize"] + v, ok = r.Header["X-Log-Bodyrawsize"] if !ok || len(v) == 0 { - err = fmt.Errorf("can't find 'x-sls-bodyrawsize' header") + err = fmt.Errorf("can't find 'x-log-bodyrawsize' header") return } bodyRawSize, err := strconv.Atoi(v[0]) diff --git a/core/logs/alils/machine_group.go b/core/logs/alils/machine_group.go index b00c480e..d47bd985 100755 --- a/core/logs/alils/machine_group.go +++ b/core/logs/alils/machine_group.go @@ -45,7 +45,7 @@ type MachineList struct { // ListMachines returns the machine list of this machine group. func (m *MachineGroup) ListMachines() (ms []*Machine, total int, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", } uri := fmt.Sprintf("/machinegroups/%v/machines", m.Name) diff --git a/core/logs/alils/request.go b/core/logs/alils/request.go index dce4dccd..b557c6dc 100755 --- a/core/logs/alils/request.go +++ b/core/logs/alils/request.go @@ -11,17 +11,17 @@ import ( func request(project *LogProject, method, uri string, headers map[string]string, body []byte) (resp *http.Response, err error) { - // The caller should provide 'x-sls-bodyrawsize' header - if _, ok := headers["x-sls-bodyrawsize"]; !ok { - err = fmt.Errorf("can't find 'x-sls-bodyrawsize' header") + // The caller should provide 'x-log-bodyrawsize' header + if _, ok := headers["x-log-bodyrawsize"]; !ok { + err = fmt.Errorf("can't find 'x-log-bodyrawsize' header") return } // SLS public request headers headers["Host"] = project.Name + "." + project.Endpoint headers["Date"] = nowRFC1123() - headers["x-sls-apiversion"] = version - headers["x-sls-signaturemethod"] = signatureMethod + headers["x-log-apiversion"] = version + headers["x-log-signaturemethod"] = signatureMethod if body != nil { bodyMD5 := fmt.Sprintf("%X", md5.Sum(body)) headers["Content-MD5"] = bodyMD5 @@ -33,12 +33,12 @@ func request(project *LogProject, method, uri string, headers map[string]string, } // Calc Authorization - // Authorization = "SLS :" + // Authorization = "LOG :" digest, err := signature(project, method, uri, headers) if err != nil { return } - auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyID, digest) + auth := fmt.Sprintf("LOG %v:%v", project.AccessKeyID, digest) headers["Authorization"] = auth // Initialize http request diff --git a/core/logs/alils/signature.go b/core/logs/alils/signature.go index 2d611307..1d0bb7d5 100755 --- a/core/logs/alils/signature.go +++ b/core/logs/alils/signature.go @@ -20,92 +20,133 @@ func nowRFC1123() string { return time.Now().In(gmtLoc).Format(time.RFC1123) } -// signature calculates a request's signature digest. +// signature calculates a request's signature digest func signature(project *LogProject, method, uri string, headers map[string]string) (digest string, err error) { - var contentMD5, contentType, date, canoHeaders, canoResource string + + // 1. Extract basic header information + contentMD5 := getHeaderSafe(headers, "Content-MD5") + contentType := getHeaderSafe(headers, "Content-Type") + + date, ok := headers["Date"] + if !ok { + return "", fmt.Errorf("Can't find 'Date' header") + } + + // 2. Calculate CanonicalizedSLSHeaders + canoHeaders := buildCanonicalHeaders(headers) + + // 3. Calculate CanonicalizedResource + canoResource, err := buildCanonicalResource(uri) + if err != nil { + return "", err + } + + // 4. Build the signature string + signStr := buildSignString(method, contentMD5, contentType, date, canoHeaders, canoResource) + + // 5. Calculate HMAC-SHA1 signature and encode with Base64 + // Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret)) + return calculateHmacSha1(signStr, project.AccessKeySecret) +} + +// getHeaderSafe safely retrieves a header value, returns empty string if not exists +func getHeaderSafe(headers map[string]string, key string) string { + if val, ok := headers[key]; ok { + return val + } + return "" +} + +// buildCanonicalHeaders constructs normalized SLS headers +func buildCanonicalHeaders(headers map[string]string) string { + slsHeaders := make(map[string]string) var slsHeaderKeys sort.StringSlice + // Extract headers prefixed with x-log- and x-acs- + for k, v := range headers { + l := strings.TrimSpace(strings.ToLower(k)) + if strings.HasPrefix(l, "x-log-") || strings.HasPrefix(l, "x-acs-") { + slsHeaders[l] = strings.TrimSpace(v) + slsHeaderKeys = append(slsHeaderKeys, l) + } + } + + // Sort headers alphabetically + sort.Sort(slsHeaderKeys) + + // Build the canonical header string + var result strings.Builder + for i, k := range slsHeaderKeys { + result.WriteString(k) + result.WriteString(":") + result.WriteString(slsHeaders[k]) + if i+1 < len(slsHeaderKeys) { + result.WriteString("\n") + } + } + + return result.String() +} + +// buildCanonicalResource constructs a normalized resource string +func buildCanonicalResource(uri string) (string, error) { + u, err := url.Parse(uri) + if err != nil { + return "", err + } + + result := u.Path + + // Process query parameters + if u.RawQuery != "" { + var keys sort.StringSlice + vals := u.Query() + + for k := range vals { + keys = append(keys, k) + } + + sort.Sort(keys) + result += "?" + + for i, k := range keys { + if i > 0 { + result += "&" + } + + for _, v := range vals[k] { + result += k + "=" + v + } + } + } + + return result, nil +} + +// buildSignString constructs the complete signature string +func buildSignString(method, contentMD5, contentType, date, canoHeaders, canoResource string) string { // SignString = VERB + "\n" // + CONTENT-MD5 + "\n" // + CONTENT-TYPE + "\n" // + DATE + "\n" // + CanonicalizedSLSHeaders + "\n" // + CanonicalizedResource - - if val, ok := headers["Content-MD5"]; ok { - contentMD5 = val - } - - if val, ok := headers["Content-Type"]; ok { - contentType = val - } - - date, ok := headers["Date"] - if !ok { - err = fmt.Errorf("Can't find 'Date' header") - return - } - - // Calc CanonicalizedSLSHeaders - slsHeaders := make(map[string]string, len(headers)) - for k, v := range headers { - l := strings.TrimSpace(strings.ToLower(k)) - if strings.HasPrefix(l, "x-sls-") { - slsHeaders[l] = strings.TrimSpace(v) - slsHeaderKeys = append(slsHeaderKeys, l) - } - } - - sort.Sort(slsHeaderKeys) - for i, k := range slsHeaderKeys { - canoHeaders += k + ":" + slsHeaders[k] - if i+1 < len(slsHeaderKeys) { - canoHeaders += "\n" - } - } - - // Calc CanonicalizedResource - u, err := url.Parse(uri) - if err != nil { - return - } - - canoResource += url.QueryEscape(u.Path) - if u.RawQuery != "" { - var keys sort.StringSlice - - vals := u.Query() - for k := range vals { - keys = append(keys, k) - } - - sort.Sort(keys) - canoResource += "?" - for i, k := range keys { - if i > 0 { - canoResource += "&" - } - - for _, v := range vals[k] { - canoResource += k + "=" + v - } - } - } - - signStr := method + "\n" + + return method + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n" + canoHeaders + "\n" + canoResource - - // Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret)) - mac := hmac.New(sha1.New, []byte(project.AccessKeySecret)) - _, err = mac.Write([]byte(signStr)) - if err != nil { - return - } - digest = base64.StdEncoding.EncodeToString(mac.Sum(nil)) - return +} + +// calculateHmacSha1 calculates the HMAC-SHA1 signature and encodes it with Base64 +func calculateHmacSha1(signStr, secret string) (string, error) { + mac := hmac.New(sha1.New, []byte(secret)) + _, err := mac.Write([]byte(signStr)) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil }