// sendRequest is an internal method to send the prepared requests to OpsGenie. func (cli *OpsGenieClient) sendRequest(req goreq.Request) (*goreq.Response, error) { // send the request var resp *goreq.Response var err error for i := 0; i < cli.httpTransportSettings.MaxRetryAttempts; i++ { resp, err = req.Do() if err == nil && resp.StatusCode < 500 { break } if resp != nil { defer resp.Body.Close() logging.Logger().Info(fmt.Sprintf("Retrying request [%s] ResponseCode:[%d]. RetryCount: %d", req.Uri, resp.StatusCode, (i + 1))) } else { logging.Logger().Info(fmt.Sprintf("Retrying request [%s] Reason:[%s]. RetryCount: %d", req.Uri, err.Error(), (i + 1))) } time.Sleep(timeSleepBetweenRequests * time.Duration(i+1)) } if err != nil { message := "Unable to send the request " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } // check for the returning http status statusCode := resp.StatusCode if statusCode >= 400 { body, err := resp.Body.ToString() if err != nil { message := "Server response with error can not be parsed " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return nil, errorMessage(statusCode, body) } return resp, nil }
func printVerboseMessage(message string) { if verbose { fmt.Printf("%s\n", message) } if log.Logger() != nil { log.Logger().Debug(fmt.Sprintf(message)) } }
// errorMessage is an internal method to return formatted error message according to HTTP status code of the response. func errorMessage(httpStatusCode int, responseBody string) error { if httpStatusCode >= 400 && httpStatusCode < 500 { message := fmt.Sprintf("Client error occurred; Response Code: %d, Response Body: %s", httpStatusCode, responseBody) logging.Logger().Warn(message) return errors.New(message) } if httpStatusCode >= 500 { message := fmt.Sprintf("Server error occurred; Response Code: %d, Response Body: %s", httpStatusCode, responseBody) logging.Logger().Info(message) return errors.New(message) } return nil }
func writeField(w multipart.Writer, fieldName string, fieldVal string) error { if err := w.WriteField(fieldName, fieldVal); err != nil { message := "Can not write field " + fieldName + " into the request. Reason: " + err.Error() logging.Logger().Warn(message) return errors.New(message) } return nil }
// buildGetRequest is an internal method to prepare a "GET" request that will send to OpsGenie. func (cli *OpsGenieClient) buildGetRequest(uri string, request interface{}) goreq.Request { req := cli.buildCommonRequestProps() req.Method = "GET" req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8" uri = cli.OpsGenieAPIUrl() + uri v, _ := goquery.Values(request) req.Uri = uri + "?" + v.Encode() logging.Logger().Info("Executing OpsGenie request to ["+uri+"] with parameters: ", v) return req }
// buildPostRequest is an internal method to prepare a "POST" request that will send to OpsGenie. func (cli *OpsGenieClient) buildPostRequest(uri string, request interface{}) goreq.Request { req := cli.buildCommonRequestProps() req.Method = "POST" req.ContentType = "application/json; charset=utf-8" req.Uri = cli.OpsGenieAPIUrl() + uri req.Body = request j, _ := json.Marshal(request) logging.Logger().Info("Executing OpsGenie request to ["+req.Uri+"] with content parameters: ", string(j)) return req }
// Disable method disables an Policy at OpsGenie. func (cli *OpsGeniePolicyClient) Disable(req policy.DisablePolicyRequest) (*policy.DisablePolicyResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildPostRequest(disablePolicyURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var disablePolicyResp policy.DisablePolicyResponse if err = resp.Body.FromJsonTo(&disablePolicyResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &disablePolicyResp, nil }
// List method retrieves teams from OpsGenie. func (cli *OpsGenieTeamClient) List(req team.ListTeamsRequest) (*team.ListTeamsResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildGetRequest(teamURL, req)) if resp == nil { return nil, errors.New(err.Error()) } defer resp.Body.Close() var listTeamsResp team.ListTeamsResponse if err = resp.Body.FromJsonTo(&listTeamsResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &listTeamsResp, nil }
// Enable method enables an Integration at OpsGenie. func (cli *OpsGenieIntegrationClient) Enable(req integration.EnableIntegrationRequest) (*integration.EnableIntegrationResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildPostRequest(enableIntegrationURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var enableIntegrationResp integration.EnableIntegrationResponse if err = resp.Body.FromJsonTo(&enableIntegrationResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &enableIntegrationResp, nil }
// Close method closes an alert at OpsGenie. func (cli *OpsGenieAlertClient) Close(req alerts.CloseAlertRequest) (*alerts.CloseAlertResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildPostRequest(closeAlertURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var closeAlertResp alerts.CloseAlertResponse if err = resp.Body.FromJsonTo(&closeAlertResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &closeAlertResp, nil }
// Update method changes configuration of an existing heartbeat at OpsGenie. func (cli *OpsGenieHeartbeatClient) Update(req heartbeat.UpdateHeartbeatRequest) (*heartbeat.UpdateHeartbeatResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildPostRequest(updateHeartbeatURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var updateHeartbeatResp heartbeat.UpdateHeartbeatResponse if err = resp.Body.FromJsonTo(&updateHeartbeatResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &updateHeartbeatResp, nil }
// Get method retrieves specified escalation details from OpsGenie. func (cli *OpsGenieEscalationClient) Get(req escalation.GetEscalationRequest) (*escalation.GetEscalationResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildGetRequest(escalationURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var getEscalationResp escalation.GetEscalationResponse if err = resp.Body.FromJsonTo(&getEscalationResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &getEscalationResp, nil }
// Get method retrieves specified schedule details from OpsGenie. func (cli *OpsGenieScheduleClient) Get(req schedule.GetScheduleRequest) (*schedule.GetScheduleResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildGetRequest(scheduleURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var getScheduleResp schedule.GetScheduleResponse if err = resp.Body.FromJsonTo(&getScheduleResp); err != nil { fmt.Println("Error parsing json") message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } fmt.Printf("%+v", getScheduleResp) return &getScheduleResp, nil }
// Delete method deletes a schedule at OpsGenie. func (cli *OpsGenieScheduleClient) Delete(req schedule.DeleteScheduleRequest) (*schedule.DeleteScheduleResponse, error) { req.APIKey = cli.apiKey resp, err := cli.sendRequest(cli.buildDeleteRequest(scheduleURL, req)) if resp == nil { return nil, err } defer resp.Body.Close() var deleteScheduleResp schedule.DeleteScheduleResponse if err = resp.Body.FromJsonTo(&deleteScheduleResp); err != nil { message := "Server response can not be parsed, " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } return &deleteScheduleResp, nil }
// AttachFile method attaches a file to an alert at OpsGenie. func (cli *OpsGenieAlertClient) AttachFile(req alerts.AttachFileAlertRequest) (*alerts.AttachFileAlertResponse, error) { req.APIKey = cli.apiKey var b bytes.Buffer w := multipart.NewWriter(&b) path := req.Attachment.Name() file, err := os.Open(path) defer file.Close() if err != nil { message := "Attachment can not be opened for reading. " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } // add the attachment fw, err := w.CreateFormFile("attachment", filepath.Base(path)) if err != nil { message := "Can not build the request with the field attachment. " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } if _, err := io.Copy(fw, file); err != nil { message := "Can not copy the attachment into the request. " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } // Add the other fields // empty fields should not be placed into the request // otherwise it yields an incomplete boundary exception if req.APIKey != "" { if err = writeField(*w, "apiKey", req.APIKey); err != nil { return nil, err } } if req.ID != "" { if err = writeField(*w, "id", req.ID); err != nil { return nil, err } } if req.Alias != "" { if err = writeField(*w, "alias", req.Alias); err != nil { return nil, err } } if req.User != "" { if err = writeField(*w, "user", req.User); err != nil { return nil, err } } if req.Source != "" { if err = writeField(*w, "source", req.Source); err != nil { return nil, err } } if req.IndexFile != "" { if err = writeField(*w, "indexFile", req.IndexFile); err != nil { return nil, err } } if req.Note != "" { if err = writeField(*w, "note", req.Note); err != nil { return nil, err } } w.Close() httpReq, err := http.NewRequest("POST", cli.opsGenieAPIURL+attachFileAlertURL, &b) if err != nil { message := "Can not create the multipart/form-data request. " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } httpReq.Header.Set("Content-Type", w.FormDataContentType()) transport := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, Proxy: http.ProxyFromEnvironment, Dial: func(netw, addr string) (net.Conn, error) { conn, err := net.DialTimeout(netw, addr, cli.httpTransportSettings.ConnectionTimeout) if err != nil { message := "Error occurred while connecting: " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } conn.SetDeadline(time.Now().Add(cli.httpTransportSettings.RequestTimeout)) return conn, nil }, } client := &http.Client{Transport: transport} // proxy settings if cli.proxy != nil { proxyURL, proxyErr := url.Parse(cli.proxy.toString()) if proxyErr != nil { message := "Can not set the proxy configuration " + proxyErr.Error() logging.Logger().Warn(message) return nil, errors.New(message) } transport.Proxy = http.ProxyURL(proxyURL) } url := httpReq.URL.String() logging.Logger().Info("Executing OpsGenie request to [" + url + "] with multipart data.") var res *http.Response for i := 0; i < cli.httpTransportSettings.MaxRetryAttempts; i++ { res, err = client.Do(httpReq) if err == nil { defer res.Body.Close() break } if res != nil { logging.Logger().Info(fmt.Sprintf("Retrying request [%s] ResponseCode:[%d]. RetryCount: %d", url, res.StatusCode, (i + 1))) } else { logging.Logger().Info(fmt.Sprintf("Retrying request [%s] Reason:[%s]. RetryCount: %d", url, err.Error(), (i + 1))) } time.Sleep(timeSleepBetweenRequests) } if err != nil { message := "Can not attach the file, unable to send the request. " + err.Error() logging.Logger().Warn(message) return nil, errors.New(message) } httpStatusCode := res.StatusCode if httpStatusCode >= 400 { body, err := ioutil.ReadAll(res.Body) if err == nil { return nil, errorMessage(httpStatusCode, string(body[:])) } message := fmt.Sprint("Couldn't read the response, %s", err.Error()) logging.Logger().Warn(message) return nil, errors.New(message) } attachFileAlertResp := alerts.AttachFileAlertResponse{Status: res.Status, Code: res.StatusCode} return &attachFileAlertResp, nil }