Chore: Disable default golangci-lint filter (#29751)

* Disable default golangci-lint filter

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Chore: Fix linter warnings

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
Arve Knudsen 2020-12-15 09:32:06 +01:00 committed by GitHub
parent 5d4910dd52
commit c2cad26ca9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 598 additions and 274 deletions

View File

@ -1,3 +1,4 @@
// Package api contains API logic.
package api package api
import ( import (
@ -7,10 +8,13 @@ import (
"github.com/grafana/grafana/pkg/api/avatar" "github.com/grafana/grafana/pkg/api/avatar"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
) )
var plog = log.New("api")
// registerRoutes registers all API HTTP routes. // registerRoutes registers all API HTTP routes.
func (hs *HTTPServer) registerRoutes() { func (hs *HTTPServer) registerRoutes() {
reqSignedIn := middleware.ReqSignedIn reqSignedIn := middleware.ReqSignedIn

View File

@ -136,7 +136,9 @@ func newNotFound() *Avatar {
// variable. // variable.
// nolint:gosec // nolint:gosec
path := filepath.Join(setting.StaticRootPath, "img", "user_profile.png") path := filepath.Join(setting.StaticRootPath, "img", "user_profile.png")
// It's safe to ignore gosec warning G304 since the variable part of the file path comes from a configuration
// variable.
// nolint:gosec
if data, err := ioutil.ReadFile(path); err != nil { if data, err := ioutil.ReadFile(path); err != nil {
log.Errorf(3, "Failed to read user_profile.png, %v", path) log.Errorf(3, "Failed to read user_profile.png, %v", path)
} else { } else {
@ -212,7 +214,10 @@ func (a *thunderTask) fetch() error {
a.Avatar.timestamp = time.Now() a.Avatar.timestamp = time.Now()
log.Debugf("avatar.fetch(fetch new avatar): %s", a.Url) log.Debugf("avatar.fetch(fetch new avatar): %s", a.Url)
req, _ := http.NewRequest("GET", a.Url, nil) req, err := http.NewRequest("GET", a.Url, nil)
if err != nil {
return err
}
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/jpeg,image/png,*/*;q=0.8") req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/jpeg,image/png,*/*;q=0.8")
req.Header.Set("Accept-Encoding", "deflate,sdch") req.Header.Set("Accept-Encoding", "deflate,sdch")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8") req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8")
@ -221,10 +226,13 @@ func (a *thunderTask) fetch() error {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
a.Avatar.notFound = true a.Avatar.notFound = true
return fmt.Errorf("gravatar unreachable, %v", err) return fmt.Errorf("gravatar unreachable: %w", err)
} }
defer func() {
defer resp.Body.Close() if err := resp.Body.Close(); err != nil {
log.Warn("Failed to close response body", "err", err)
}
}()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
a.Avatar.notFound = true a.Avatar.notFound = true

View File

@ -54,7 +54,11 @@ func createExternalDashboardSnapshot(cmd models.CreateDashboardSnapshotCommand)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer response.Body.Close() defer func() {
if err := response.Body.Close(); err != nil {
plog.Warn("Failed to close response body", "err", err)
}
}()
if response.StatusCode != 200 { if response.StatusCode != 200 {
return nil, fmt.Errorf("create external snapshot response status code %d", response.StatusCode) return nil, fmt.Errorf("create external snapshot response status code %d", response.StatusCode)
@ -178,7 +182,9 @@ func deleteExternalDashboardSnapshot(externalUrl string) error {
if err != nil { if err != nil {
return err return err
} }
defer response.Body.Close() if err := response.Body.Close(); err != nil {
plog.Warn("Failed closing response body", "err", err)
}
if response.StatusCode == 200 { if response.StatusCode == 200 {
return nil return nil

View File

@ -19,7 +19,7 @@ var (
getLDAPConfig = multildap.GetConfig getLDAPConfig = multildap.GetConfig
newLDAP = multildap.New newLDAP = multildap.New
logger = log.New("LDAP.debug") ldapLogger = log.New("LDAP.debug")
errOrganizationNotFound = func(orgId int64) error { errOrganizationNotFound = func(orgId int64) error {
return fmt.Errorf("unable to find organization with ID '%d'", orgId) return fmt.Errorf("unable to find organization with ID '%d'", orgId)
@ -117,7 +117,6 @@ func (hs *HTTPServer) GetLDAPStatus(c *models.ReqContext) Response {
} }
ldapConfig, err := getLDAPConfig(hs.Cfg) ldapConfig, err := getLDAPConfig(hs.Cfg)
if err != nil { if err != nil {
return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err) return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err)
} }
@ -129,7 +128,6 @@ func (hs *HTTPServer) GetLDAPStatus(c *models.ReqContext) Response {
} }
statuses, err := ldap.Ping() statuses, err := ldap.Ping()
if err != nil { if err != nil {
return Error(http.StatusBadRequest, "Failed to connect to the LDAP server(s)", err) return Error(http.StatusBadRequest, "Failed to connect to the LDAP server(s)", err)
} }
@ -187,12 +185,11 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response {
ldapServer := newLDAP(ldapConfig.Servers) ldapServer := newLDAP(ldapConfig.Servers)
user, _, err := ldapServer.User(query.Result.Login) user, _, err := ldapServer.User(query.Result.Login)
if err != nil { if err != nil {
if errors.Is(err, multildap.ErrDidNotFindUser) { // User was not in the LDAP server - we need to take action: if errors.Is(err, multildap.ErrDidNotFindUser) { // User was not in the LDAP server - we need to take action:
if setting.AdminUser == query.Result.Login { // User is *the* Grafana Admin. We cannot disable it. if setting.AdminUser == query.Result.Login { // User is *the* Grafana Admin. We cannot disable it.
errMsg := fmt.Sprintf(`Refusing to sync grafana super admin "%s" - it would be disabled`, query.Result.Login) errMsg := fmt.Sprintf(`Refusing to sync grafana super admin "%s" - it would be disabled`, query.Result.Login)
logger.Error(errMsg) ldapLogger.Error(errMsg)
return Error(http.StatusBadRequest, errMsg, err) return Error(http.StatusBadRequest, errMsg, err)
} }
@ -210,7 +207,7 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response {
return Error(http.StatusBadRequest, "User not found in LDAP. Disabled the user without updating information", nil) // should this be a success? return Error(http.StatusBadRequest, "User not found in LDAP. Disabled the user without updating information", nil) // should this be a success?
} }
logger.Debug("Failed to sync the user with LDAP", "err", err) ldapLogger.Debug("Failed to sync the user with LDAP", "err", err)
return Error(http.StatusBadRequest, "Something went wrong while finding the user in LDAP", err) return Error(http.StatusBadRequest, "Something went wrong while finding the user in LDAP", err)
} }
@ -221,7 +218,6 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response {
} }
err = bus.Dispatch(upsertCmd) err = bus.Dispatch(upsertCmd)
if err != nil { if err != nil {
return Error(http.StatusInternalServerError, "Failed to update the user", err) return Error(http.StatusInternalServerError, "Failed to update the user", err)
} }
@ -236,7 +232,6 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response {
} }
ldapConfig, err := getLDAPConfig(hs.Cfg) ldapConfig, err := getLDAPConfig(hs.Cfg)
if err != nil { if err != nil {
return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err) return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err)
} }
@ -255,7 +250,7 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response {
return Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err) return Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err)
} }
logger.Debug("user found", "user", user) ldapLogger.Debug("user found", "user", user)
name, surname := splitName(user.Name) name, surname := splitName(user.Name)
@ -304,16 +299,14 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response {
u.OrgRoles = orgRoles u.OrgRoles = orgRoles
logger.Debug("mapping org roles", "orgsRoles", u.OrgRoles) ldapLogger.Debug("mapping org roles", "orgsRoles", u.OrgRoles)
err = u.FetchOrgs() err = u.FetchOrgs()
if err != nil { if err != nil {
return Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err) return Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err)
} }
cmd := &models.GetTeamsForLDAPGroupCommand{Groups: user.Groups} cmd := &models.GetTeamsForLDAPGroupCommand{Groups: user.Groups}
err = bus.Dispatch(cmd) err = bus.Dispatch(cmd)
if err != nil && !errors.Is(err, bus.ErrHandlerNotFound) { if err != nil && !errors.Is(err, bus.ErrHandlerNotFound) {
return Error(http.StatusBadRequest, "Unable to find the teams for this user", err) return Error(http.StatusBadRequest, "Unable to find the teams for this user", err)
} }

View File

@ -224,11 +224,11 @@ func buildExternalUserInfo(token *oauth2.Token, userInfo *social.BasicUserInfo,
var orgID int64 var orgID int64
if setting.AutoAssignOrg && setting.AutoAssignOrgId > 0 { if setting.AutoAssignOrg && setting.AutoAssignOrgId > 0 {
orgID = int64(setting.AutoAssignOrgId) orgID = int64(setting.AutoAssignOrgId)
logger.Debug("The user has a role assignment and organization membership is auto-assigned", plog.Debug("The user has a role assignment and organization membership is auto-assigned",
"role", userInfo.Role, "orgId", orgID) "role", userInfo.Role, "orgId", orgID)
} else { } else {
orgID = int64(1) orgID = int64(1)
logger.Debug("The user has a role assignment and organization membership is not auto-assigned", plog.Debug("The user has a role assignment and organization membership is not auto-assigned",
"role", userInfo.Role, "orgId", orgID) "role", userInfo.Role, "orgId", orgID)
} }
extUser.OrgRoles[orgID] = rt extUser.OrgRoles[orgID] = rt

View File

@ -113,7 +113,10 @@ func (provider *accessTokenProvider) getAccessToken(data templateData) (string,
params.Add(key, interpolatedParam) params.Add(key, interpolatedParam)
} }
getTokenReq, _ := http.NewRequest("POST", urlInterpolated, bytes.NewBufferString(params.Encode())) getTokenReq, err := http.NewRequest("POST", urlInterpolated, bytes.NewBufferString(params.Encode()))
if err != nil {
return "", err
}
getTokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") getTokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
getTokenReq.Header.Set("Content-Length", strconv.Itoa(len(params.Encode()))) getTokenReq.Header.Set("Content-Length", strconv.Itoa(len(params.Encode())))
@ -122,7 +125,11 @@ func (provider *accessTokenProvider) getAccessToken(data templateData) (string,
return "", err return "", err
} }
defer resp.Body.Close() defer func() {
if err := resp.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
var token jwtToken var token jwtToken
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil { if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {

View File

@ -134,7 +134,11 @@ func staticHandler(ctx *macaron.Context, log *log.Logger, opt StaticOptions) boo
if err != nil { if err != nil {
return false return false
} }
defer f.Close() defer func() {
if err := f.Close(); err != nil {
log.Printf("Failed to close file: %s\n", err)
}
}()
fi, err := f.Stat() fi, err := f.Stat()
if err != nil { if err != nil {
@ -154,7 +158,11 @@ func staticHandler(ctx *macaron.Context, log *log.Logger, opt StaticOptions) boo
if err != nil { if err != nil {
return false // Discard error. return false // Discard error.
} }
defer f.Close() defer func() {
if err := f.Close(); err != nil {
log.Printf("Failed to close file: %s", err)
}
}()
fi, err = f.Stat() fi, err = f.Stat()
if err != nil || fi.IsDir() { if err != nil || fi.IsDir() {
@ -163,7 +171,7 @@ func staticHandler(ctx *macaron.Context, log *log.Logger, opt StaticOptions) boo
} }
if !opt.SkipLogging { if !opt.SkipLogging {
log.Println("[Static] Serving " + file) log.Printf("[Static] Serving %s\n", file)
} }
// Add an Expires header to the static content // Add an Expires header to the static content

View File

@ -111,11 +111,17 @@ func InstallPlugin(pluginName, version string, c utils.CommandLine, client utils
if err != nil { if err != nil {
return errutil.Wrap("failed to create temporary file", err) return errutil.Wrap("failed to create temporary file", err)
} }
defer os.Remove(tmpFile.Name()) defer func() {
if err := os.Remove(tmpFile.Name()); err != nil {
logger.Warn("Failed to remove temporary file", "file", tmpFile.Name(), "err", err)
}
}()
err = client.DownloadFile(pluginName, tmpFile, downloadURL, checksum) err = client.DownloadFile(pluginName, tmpFile, downloadURL, checksum)
if err != nil { if err != nil {
tmpFile.Close() if err := tmpFile.Close(); err != nil {
logger.Warn("Failed to close file", "err", err)
}
return errutil.Wrap("failed to download plugin archive", err) return errutil.Wrap("failed to download plugin archive", err)
} }
err = tmpFile.Close() err = tmpFile.Close()
@ -228,6 +234,8 @@ func extractFiles(archiveFile string, pluginName string, filePath string, allowS
newFile := filepath.Join(filePath, newFileName) newFile := filepath.Join(filePath, newFileName)
if zf.FileInfo().IsDir() { if zf.FileInfo().IsDir() {
// We can ignore gosec G304 here since it makes sense to give all users read access
// nolint:gosec
if err := os.MkdirAll(newFile, 0755); err != nil { if err := os.MkdirAll(newFile, 0755); err != nil {
if os.IsPermission(err) { if os.IsPermission(err) {
return fmt.Errorf(permissionsDeniedMessage, newFile) return fmt.Errorf(permissionsDeniedMessage, newFile)
@ -240,6 +248,8 @@ func extractFiles(archiveFile string, pluginName string, filePath string, allowS
} }
// Create needed directories to extract file // Create needed directories to extract file
// We can ignore gosec G304 here since it makes sense to give all users read access
// nolint:gosec
if err := os.MkdirAll(filepath.Dir(newFile), 0755); err != nil { if err := os.MkdirAll(filepath.Dir(newFile), 0755); err != nil {
return errutil.Wrap("failed to create directory to extract plugin files", err) return errutil.Wrap("failed to create directory to extract plugin files", err)
} }

View File

@ -215,7 +215,7 @@ func setupFakePluginsDir(t *testing.T) (string, func()) {
err := os.RemoveAll(dirname) err := os.RemoveAll(dirname)
require.Nil(t, err) require.Nil(t, err)
err = os.MkdirAll(dirname, 0774) err = os.MkdirAll(dirname, 0750)
require.Nil(t, err) require.Nil(t, err)
return dirname, func() { return dirname, func() {

View File

@ -94,14 +94,20 @@ func (client *GrafanaComClient) DownloadFile(pluginName string, tmpFile *os.File
if err != nil { if err != nil {
return errutil.Wrap("Failed to send request", err) return errutil.Wrap("Failed to send request", err)
} }
defer bodyReader.Close() defer func() {
if err := bodyReader.Close(); err != nil {
logger.Warn("Failed to close body", "err", err)
}
}()
w := bufio.NewWriter(tmpFile) w := bufio.NewWriter(tmpFile)
h := md5.New() h := md5.New()
if _, err = io.Copy(w, io.TeeReader(bodyReader, h)); err != nil { if _, err = io.Copy(w, io.TeeReader(bodyReader, h)); err != nil {
return errutil.Wrap("Failed to compute MD5 checksum", err) return errutil.Wrap("Failed to compute MD5 checksum", err)
} }
w.Flush() if err := w.Flush(); err != nil {
return fmt.Errorf("failed to write to %q: %w", tmpFile.Name(), err)
}
if len(checksum) > 0 && checksum != fmt.Sprintf("%x", h.Sum(nil)) { if len(checksum) > 0 && checksum != fmt.Sprintf("%x", h.Sum(nil)) {
return fmt.Errorf("expected MD5 checksum does not match the downloaded archive - please contact security@grafana.com") return fmt.Errorf("expected MD5 checksum does not match the downloaded archive - please contact security@grafana.com")
} }
@ -131,7 +137,11 @@ func sendRequestGetBytes(client http.Client, repoUrl string, subPaths ...string)
if err != nil { if err != nil {
return []byte{}, err return []byte{}, err
} }
defer bodyReader.Close() defer func() {
if err := bodyReader.Close(); err != nil {
logger.Warn("Failed to close stream", "err", err)
}
}()
return ioutil.ReadAll(bodyReader) return ioutil.ReadAll(bodyReader)
} }
@ -182,7 +192,11 @@ func handleResponse(res *http.Response) (io.ReadCloser, error) {
if res.StatusCode/100 == 4 { if res.StatusCode/100 == 4 {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close() defer func() {
if err := res.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
if err != nil || len(body) == 0 { if err != nil || len(body) == 0 {
return nil, &BadRequestError{Status: res.Status} return nil, &BadRequestError{Status: res.Status}
} }

View File

@ -14,8 +14,9 @@ import (
func TestHandleResponse(t *testing.T) { func TestHandleResponse(t *testing.T) {
t.Run("Returns body if status == 200", func(t *testing.T) { t.Run("Returns body if status == 200", func(t *testing.T) {
resp := makeResponse(200, "test") // The body gets closed within makeResponse
defer resp.Body.Close() // nolint:bodyclose
resp := makeResponse(t, 200, "test")
bodyReader, err := handleResponse(resp) bodyReader, err := handleResponse(resp)
require.NoError(t, err) require.NoError(t, err)
body, err := ioutil.ReadAll(bodyReader) body, err := ioutil.ReadAll(bodyReader)
@ -24,54 +25,68 @@ func TestHandleResponse(t *testing.T) {
}) })
t.Run("Returns ErrorNotFound if status == 404", func(t *testing.T) { t.Run("Returns ErrorNotFound if status == 404", func(t *testing.T) {
resp := makeResponse(404, "") // The body gets closed within makeResponse
defer resp.Body.Close() // nolint:bodyclose
resp := makeResponse(t, 404, "")
_, err := handleResponse(resp) _, err := handleResponse(resp)
assert.Equal(t, ErrNotFoundError, err) assert.Equal(t, ErrNotFoundError, err)
}) })
t.Run("Returns message from body if status == 400", func(t *testing.T) { t.Run("Returns message from body if status == 400", func(t *testing.T) {
resp := makeResponse(400, "{ \"message\": \"error_message\" }") // The body gets closed within makeResponse
defer resp.Body.Close() // nolint:bodyclose
resp := makeResponse(t, 400, "{ \"message\": \"error_message\" }")
_, err := handleResponse(resp) _, err := handleResponse(resp)
require.Error(t, err) require.Error(t, err)
assert.Equal(t, "error_message", asBadRequestError(t, err).Message) assert.Equal(t, "error_message", asBadRequestError(t, err).Message)
}) })
t.Run("Returns body if status == 400 and no message key", func(t *testing.T) { t.Run("Returns body if status == 400 and no message key", func(t *testing.T) {
resp := makeResponse(400, "{ \"test\": \"test_message\"}") // The body gets closed within makeResponse
defer resp.Body.Close() // nolint:bodyclose
resp := makeResponse(t, 400, "{ \"test\": \"test_message\"}")
_, err := handleResponse(resp) _, err := handleResponse(resp)
require.Error(t, err) require.Error(t, err)
assert.Equal(t, "{ \"test\": \"test_message\"}", asBadRequestError(t, err).Message) assert.Equal(t, "{ \"test\": \"test_message\"}", asBadRequestError(t, err).Message)
}) })
t.Run("Returns Bad request error if status == 400 and no body", func(t *testing.T) { t.Run("Returns Bad request error if status == 400 and no body", func(t *testing.T) {
resp := makeResponse(400, "") // The body gets closed within makeResponse
defer resp.Body.Close() // nolint:bodyclose
resp := makeResponse(t, 400, "")
_, err := handleResponse(resp) _, err := handleResponse(resp)
require.Error(t, err) require.Error(t, err)
_ = asBadRequestError(t, err) _ = asBadRequestError(t, err)
}) })
t.Run("Returns error with invalid status if status == 500", func(t *testing.T) { t.Run("Returns error with invalid status if status == 500", func(t *testing.T) {
resp := makeResponse(500, "") // The body gets closed within makeResponse
defer resp.Body.Close() // nolint:bodyclose
resp := makeResponse(t, 500, "")
_, err := handleResponse(resp) _, err := handleResponse(resp)
require.Error(t, err) require.Error(t, err)
assert.Contains(t, err.Error(), "invalid status") assert.Contains(t, err.Error(), "invalid status")
}) })
} }
func makeResponse(status int, body string) *http.Response { func makeResponse(t *testing.T, status int, body string) *http.Response {
t.Helper()
return &http.Response{ return &http.Response{
StatusCode: status, StatusCode: status,
Body: makeBody(body), Body: makeBody(t, body),
} }
} }
func makeBody(body string) io.ReadCloser { func makeBody(t *testing.T, body string) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(body))) t.Helper()
reader := ioutil.NopCloser(bytes.NewReader([]byte(body)))
t.Cleanup(func() {
err := reader.Close()
assert.NoError(t, err)
})
return reader
} }
func asBadRequestError(t *testing.T, err error) *BadRequestError { func asBadRequestError(t *testing.T, err error) *BadRequestError {

View File

@ -108,7 +108,11 @@ func main() {
} }
func executeServer(configFile, homePath, pidFile, packaging string, traceDiagnostics *tracingDiagnostics) error { func executeServer(configFile, homePath, pidFile, packaging string, traceDiagnostics *tracingDiagnostics) error {
defer log.Close() defer func() {
if err := log.Close(); err != nil {
fmt.Fprintf(os.Stderr, "Failed to close log: %s\n", err)
}
}()
if traceDiagnostics.enabled { if traceDiagnostics.enabled {
fmt.Println("diagnostics: tracing enabled", "file", traceDiagnostics.file) fmt.Println("diagnostics: tracing enabled", "file", traceDiagnostics.file)
@ -183,7 +187,9 @@ func listenToSystemSignals(s *server.Server) {
for { for {
select { select {
case <-sighupChan: case <-sighupChan:
log.Reload() if err := log.Reload(); err != nil {
fmt.Fprintf(os.Stderr, "Failed to reload loggers: %s\n", err)
}
case sig := <-signalChan: case sig := <-signalChan:
s.Shutdown(fmt.Sprintf("System signal: %s", sig)) s.Shutdown(fmt.Sprintf("System signal: %s", sig))
} }

View File

@ -70,9 +70,17 @@ func (az *AzureBlobUploader) Upload(ctx context.Context, imageDiskPath string) (
if err != nil { if err != nil {
return "", err return "", err
} }
defer func() {
if err := resp.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
if resp.StatusCode > 400 && resp.StatusCode < 600 { if resp.StatusCode > 400 && resp.StatusCode < 600 {
body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", err
}
aerr := &Error{ aerr := &Error{
Code: resp.StatusCode, Code: resp.StatusCode,
Status: resp.Status, Status: resp.Status,
@ -80,7 +88,6 @@ func (az *AzureBlobUploader) Upload(ctx context.Context, imageDiskPath string) (
Header: resp.Header, Header: resp.Header,
} }
aerr.parseXML() aerr.parseXML()
resp.Body.Close()
return "", aerr return "", aerr
} }

View File

@ -78,10 +78,17 @@ func (u *WebdavUploader) Upload(ctx context.Context, imgToUpload string) (string
if err != nil { if err != nil {
return "", err return "", err
} }
defer res.Body.Close() defer func() {
if err := res.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
if res.StatusCode != http.StatusCreated { if res.StatusCode != http.StatusCreated {
body, _ := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", fmt.Errorf("failed to read response body: %w", err)
}
return "", fmt.Errorf("failed to upload image, statuscode: %d, body: %s", res.StatusCode, body) return "", fmt.Errorf("failed to upload image, statuscode: %d, body: %s", res.StatusCode, body)
} }

View File

@ -5,6 +5,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -18,7 +19,10 @@ func TestExists_NonExistent(t *testing.T) {
func TestExists_Existent(t *testing.T) { func TestExists_Existent(t *testing.T) {
f, err := ioutil.TempFile("", "") f, err := ioutil.TempFile("", "")
require.NoError(t, err) require.NoError(t, err)
defer os.Remove(f.Name()) t.Cleanup(func() {
err := os.Remove(f.Name())
assert.NoError(t, err)
})
exists, err := Exists(f.Name()) exists, err := Exists(f.Name())
require.NoError(t, err) require.NoError(t, err)

View File

@ -55,11 +55,15 @@ func (l *MuxWriter) Write(b []byte) (int, error) {
} }
// set os.File in writer. // set os.File in writer.
func (l *MuxWriter) SetFd(fd *os.File) { func (l *MuxWriter) setFD(fd *os.File) error {
if l.fd != nil { if l.fd != nil {
l.fd.Close() if err := l.fd.Close(); err != nil {
return err
}
} }
l.fd = fd l.fd = fd
return nil
} }
// create a FileLogWriter returning as LoggerInterface. // create a FileLogWriter returning as LoggerInterface.
@ -98,13 +102,17 @@ func (w *FileLogWriter) StartLogger() error {
if err != nil { if err != nil {
return err return err
} }
w.mw.SetFd(fd) if err := w.mw.setFD(fd); err != nil {
return err
}
return w.initFd() return w.initFd()
} }
func (w *FileLogWriter) docheck(size int) { func (w *FileLogWriter) docheck(size int) {
w.startLock.Lock() w.startLock.Lock()
defer w.startLock.Unlock() defer w.startLock.Unlock()
if w.Rotate && ((w.Maxlines > 0 && w.maxlinesCurlines >= w.Maxlines) || if w.Rotate && ((w.Maxlines > 0 && w.maxlinesCurlines >= w.Maxlines) ||
(w.Maxsize > 0 && w.maxsizeCursize >= w.Maxsize) || (w.Maxsize > 0 && w.maxsizeCursize >= w.Maxsize) ||
(w.Daily && time.Now().Day() != w.dailyOpendate)) { (w.Daily && time.Now().Day() != w.dailyOpendate)) {
@ -119,6 +127,9 @@ func (w *FileLogWriter) docheck(size int) {
func (w *FileLogWriter) createLogFile() (*os.File, error) { func (w *FileLogWriter) createLogFile() (*os.File, error) {
// Open the log file // Open the log file
// We can ignore G304 here since we can't unconditionally lock these log files down to be readable only
// by the owner
// nolint:gosec
return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
} }
@ -187,7 +198,9 @@ func (w *FileLogWriter) DoRotate() error {
defer w.mw.Unlock() defer w.mw.Unlock()
fd := w.mw.fd fd := w.mw.fd
fd.Close() if err := fd.Close(); err != nil {
return err
}
// close fd before rename // close fd before rename
// Rename the file to its newfound home // Rename the file to its newfound home
@ -228,8 +241,8 @@ func (w *FileLogWriter) deleteOldLog() {
} }
// destroy file logger, close file writer. // destroy file logger, close file writer.
func (w *FileLogWriter) Close() { func (w *FileLogWriter) Close() error {
w.mw.fd.Close() return w.mw.fd.Close()
} }
// flush file logger. // flush file logger.
@ -242,18 +255,22 @@ func (w *FileLogWriter) Flush() {
} }
// Reload file logger // Reload file logger
func (w *FileLogWriter) Reload() { func (w *FileLogWriter) Reload() error {
// block Logger's io.Writer // block Logger's io.Writer
w.mw.Lock() w.mw.Lock()
defer w.mw.Unlock() defer w.mw.Unlock()
// Close // Close
fd := w.mw.fd fd := w.mw.fd
fd.Close() if err := fd.Close(); err != nil {
return err
}
// Open again // Open again
err := w.StartLogger() err := w.StartLogger()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Reload StartLogger: %s\n", err) return err
} }
return nil
} }

View File

@ -23,9 +23,10 @@ func TestLogFile(t *testing.T) {
require.NotNil(t, fileLogWrite) require.NotNil(t, fileLogWrite)
t.Cleanup(func() { t.Cleanup(func() {
fileLogWrite.Close() err := fileLogWrite.Close()
err := os.Remove(fileLogWrite.Filename) assert.NoError(t, err)
require.NoError(t, err) err = os.Remove(fileLogWrite.Filename)
assert.NoError(t, err)
}) })
fileLogWrite.Filename = "grafana_test.log" fileLogWrite.Filename = "grafana_test.log"

View File

@ -1,9 +1,9 @@
package log package log
type DisposableHandler interface { type DisposableHandler interface {
Close() Close() error
} }
type ReloadableHandler interface { type ReloadableHandler interface {
Reload() Reload() error
} }

View File

@ -69,6 +69,10 @@ func Infof(format string, v ...interface{}) {
Root.Info(message) Root.Info(message)
} }
func Warn(msg string, v ...interface{}) {
Root.Warn(msg, v...)
}
func Warnf(format string, v ...interface{}) { func Warnf(format string, v ...interface{}) {
var message string var message string
if len(v) > 0 { if len(v) > 0 {
@ -90,21 +94,33 @@ func Errorf(skip int, format string, v ...interface{}) {
func Fatalf(skip int, format string, v ...interface{}) { func Fatalf(skip int, format string, v ...interface{}) {
Root.Crit(fmt.Sprintf(format, v...)) Root.Crit(fmt.Sprintf(format, v...))
Close() if err := Close(); err != nil {
fmt.Fprintf(os.Stderr, "Failed to close log: %s\n", err)
}
os.Exit(1) os.Exit(1)
} }
func Close() { func Close() error {
var err error
for _, logger := range loggersToClose { for _, logger := range loggersToClose {
logger.Close() if e := logger.Close(); e != nil && err == nil {
err = e
}
} }
loggersToClose = make([]DisposableHandler, 0) loggersToClose = make([]DisposableHandler, 0)
return err
} }
func Reload() { // Reload reloads all loggers.
func Reload() error {
for _, logger := range loggersToReload { for _, logger := range loggersToReload {
logger.Reload() if err := logger.Reload(); err != nil {
return err
}
} }
return nil
} }
var logLevels = map[string]log15.Lvl{ var logLevels = map[string]log15.Lvl{
@ -164,7 +180,9 @@ func getLogFormat(format string) log15.Format {
} }
func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error { func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error {
Close() if err := Close(); err != nil {
return err
}
defaultLevelName, _ := getLogLevelFromConfig("log", "info", cfg) defaultLevelName, _ := getLogLevelFromConfig("log", "info", cfg)
defaultFilters := getFilters(util.SplitString(cfg.Section("log").Key("filters").String())) defaultFilters := getFilters(util.SplitString(cfg.Section("log").Key("filters").String()))

View File

@ -77,8 +77,8 @@ func (sw *SysLogHandler) Log(r *log15.Record) error {
return err return err
} }
func (sw *SysLogHandler) Close() { func (sw *SysLogHandler) Close() error {
sw.syslog.Close() return sw.syslog.Close()
} }
var facilities = map[string]syslog.Priority{ var facilities = map[string]syslog.Priority{

View File

@ -18,5 +18,6 @@ func (sw *SysLogHandler) Log(r *log15.Record) error {
return nil return nil
} }
func (sw *SysLogHandler) Close() { func (sw *SysLogHandler) Close() error {
return nil
} }

View File

@ -27,6 +27,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt" "github.com/prometheus/common/expfmt"
@ -201,7 +202,11 @@ func (b *Bridge) Push() error {
if err != nil { if err != nil {
return err return err
} }
defer conn.Close() defer func() {
if err := conn.Close(); err != nil {
logger.Warn("Failed to close connection", "err", err)
}
}()
return b.writeMetrics(conn, mfs, b.prefix, model.Now()) return b.writeMetrics(conn, mfs, b.prefix, model.Now())
} }

View File

@ -12,14 +12,16 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestCountersAsDelta(t *testing.T) { func TestCountersAsDelta(t *testing.T) {
b, _ := NewBridge(&Config{ b, err := NewBridge(&Config{
URL: "localhost:12345", URL: "localhost:12345",
CountersAsDelta: true, CountersAsDelta: true,
}) })
require.NoError(t, err)
ty := dto.MetricType(0) ty := dto.MetricType(0)
mf := &dto.MetricFamily{ mf := &dto.MetricFamily{
Type: &ty, Type: &ty,
@ -442,29 +444,21 @@ func TestSkipNanValues(t *testing.T) {
Gatherer: reg, Gatherer: reg,
CountersAsDelta: true, CountersAsDelta: true,
}) })
if err != nil { require.NoError(t, err)
t.Fatalf("error creating bridge: %v", err)
}
// first collect // first collect
mfs, err := reg.Gather() mfs, err := reg.Gather()
if err != nil { require.NoError(t, err)
t.Fatalf("error: %v", err)
}
var buf bytes.Buffer var buf bytes.Buffer
err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477043083)) err = b.writeMetrics(&buf, mfs, "prefix.", model.Time(1477043083))
if err != nil { require.NoError(t, err)
t.Fatalf("error: %v", err)
}
want := `prefix.http_request_total_sum.constname.constvalue 0 1477043 want := `prefix.http_request_total_sum.constname.constvalue 0 1477043
prefix.http_request_total_count.constname.constvalue.count 0 1477043 prefix.http_request_total_count.constname.constvalue.count 0 1477043
` `
if got := buf.String(); want != got { assert.Equal(t, want, buf.String())
t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
}
} }
func TestPush(t *testing.T) { func TestPush(t *testing.T) {
@ -489,20 +483,17 @@ func TestPush(t *testing.T) {
Gatherer: reg, Gatherer: reg,
Prefix: "prefix.", Prefix: "prefix.",
}) })
if err != nil { require.NoError(t, err)
t.Fatalf("error creating bridge: %v", err)
}
nmg, err := newMockGraphite(port) nmg, err := newMockGraphite(port)
if err != nil { require.NoError(t, err)
t.Fatalf("error creating mock graphite: %v", err) t.Cleanup(func() {
} err := nmg.Close()
defer nmg.Close() require.NoError(t, err)
})
err = b.Push() err = b.Push()
if err != nil { require.NoError(t, err)
t.Fatalf("error pushing: %v", err)
}
wants := []string{ wants := []string{
"prefix.name.constname.constvalue.labelname.val1.count 1", "prefix.name.constname.constvalue.labelname.val1.count 1",

View File

@ -130,7 +130,7 @@ func (ts *TracingService) Run(ctx context.Context) error {
if ts.closer != nil { if ts.closer != nil {
ts.log.Info("Closing tracing") ts.log.Info("Closing tracing")
ts.closer.Close() return ts.closer.Close()
} }
return nil return nil

View File

@ -58,9 +58,11 @@ func TestInitJaegerCfg_Enabled(t *testing.T) {
} }
func TestInitJaegerCfg_DisabledViaEnv(t *testing.T) { func TestInitJaegerCfg_DisabledViaEnv(t *testing.T) {
os.Setenv("JAEGER_DISABLED", "true") err := os.Setenv("JAEGER_DISABLED", "true")
require.NoError(t, err)
defer func() { defer func() {
os.Unsetenv("JAEGER_DISABLED") err := os.Unsetenv("JAEGER_DISABLED")
require.NoError(t, err)
}() }()
ts := &TracingService{enabled: true} ts := &TracingService{enabled: true}
@ -71,9 +73,11 @@ func TestInitJaegerCfg_DisabledViaEnv(t *testing.T) {
} }
func TestInitJaegerCfg_EnabledViaEnv(t *testing.T) { func TestInitJaegerCfg_EnabledViaEnv(t *testing.T) {
os.Setenv("JAEGER_DISABLED", "false") err := os.Setenv("JAEGER_DISABLED", "false")
require.NoError(t, err)
defer func() { defer func() {
os.Unsetenv("JAEGER_DISABLED") err := os.Unsetenv("JAEGER_DISABLED")
require.NoError(t, err)
}() }()
ts := &TracingService{enabled: false} ts := &TracingService{enabled: false}
@ -84,12 +88,14 @@ func TestInitJaegerCfg_EnabledViaEnv(t *testing.T) {
} }
func TestInitJaegerCfg_InvalidEnvVar(t *testing.T) { func TestInitJaegerCfg_InvalidEnvVar(t *testing.T) {
os.Setenv("JAEGER_DISABLED", "totallybogus") err := os.Setenv("JAEGER_DISABLED", "totallybogus")
require.NoError(t, err)
defer func() { defer func() {
os.Unsetenv("JAEGER_DISABLED") err := os.Unsetenv("JAEGER_DISABLED")
require.NoError(t, err)
}() }()
ts := &TracingService{} ts := &TracingService{}
_, err := ts.initJaegerCfg() _, err = ts.initJaegerCfg()
require.EqualError(t, err, "cannot parse env var JAEGER_DISABLED=totallybogus: strconv.ParseBool: parsing \"totallybogus\": invalid syntax") require.EqualError(t, err, "cannot parse env var JAEGER_DISABLED=totallybogus: strconv.ParseBool: parsing \"totallybogus\": invalid syntax")
} }

View File

@ -50,7 +50,9 @@ func (uss *UsageStatsService) Run(ctx context.Context) error {
for { for {
select { select {
case <-onceEveryDayTick.C: case <-onceEveryDayTick.C:
uss.sendUsageStats() if err := uss.sendUsageStats(); err != nil {
metricsLogger.Warn("Failed to send usage stats", "err", err)
}
case <-everyMinuteTicker.C: case <-everyMinuteTicker.C:
uss.updateTotalStats() uss.updateTotalStats()
case <-ctx.Done(): case <-ctx.Done():

View File

@ -186,19 +186,22 @@ func (uss *UsageStatsService) GetUsageReport() (UsageReport, error) {
return report, nil return report, nil
} }
func (uss *UsageStatsService) sendUsageStats() { func (uss *UsageStatsService) sendUsageStats() error {
if !setting.ReportingEnabled { if !setting.ReportingEnabled {
return return nil
} }
metricsLogger.Debug(fmt.Sprintf("Sending anonymous usage stats to %s", usageStatsURL)) metricsLogger.Debug(fmt.Sprintf("Sending anonymous usage stats to %s", usageStatsURL))
report, err := uss.GetUsageReport() report, err := uss.GetUsageReport()
if err != nil { if err != nil {
return return err
} }
out, _ := json.MarshalIndent(report, "", " ") out, err := json.MarshalIndent(report, "", " ")
if err != nil {
return err
}
data := bytes.NewBuffer(out) data := bytes.NewBuffer(out)
client := http.Client{Timeout: 5 * time.Second} client := http.Client{Timeout: 5 * time.Second}
@ -208,8 +211,12 @@ func (uss *UsageStatsService) sendUsageStats() {
metricsLogger.Error("Failed to send usage stats", "err", err) metricsLogger.Error("Failed to send usage stats", "err", err)
return return
} }
resp.Body.Close() if err := resp.Body.Close(); err != nil {
metricsLogger.Warn("Failed to close response body", "err", err)
}
}() }()
return nil
} }
func (uss *UsageStatsService) updateTotalStats() { func (uss *UsageStatsService) updateTotalStats() {

View File

@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/licensing" "github.com/grafana/grafana/pkg/services/licensing"
"github.com/stretchr/testify/require"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -171,11 +172,13 @@ func TestMetrics(t *testing.T) {
"grafana_com": true, "grafana_com": true,
} }
uss.sendUsageStats() err := uss.sendUsageStats()
require.NoError(t, err)
Convey("Given reporting not enabled and sending usage stats", func() { Convey("Given reporting not enabled and sending usage stats", func() {
setting.ReportingEnabled = false setting.ReportingEnabled = false
uss.sendUsageStats() err := uss.sendUsageStats()
require.NoError(t, err)
Convey("Should not gather stats or call http endpoint", func() { Convey("Should not gather stats or call http endpoint", func() {
So(getSystemStatsQuery, ShouldBeNil) So(getSystemStatsQuery, ShouldBeNil)
@ -195,7 +198,8 @@ func TestMetrics(t *testing.T) {
setting.Packaging = "deb" setting.Packaging = "deb"
wg.Add(1) wg.Add(1)
uss.sendUsageStats() err := uss.sendUsageStats()
require.NoError(t, err)
Convey("Should gather stats and call http endpoint", func() { Convey("Should gather stats and call http endpoint", func() {
if waitTimeout(&wg, 2*time.Second) { if waitTimeout(&wg, 2*time.Second) {

View File

@ -56,7 +56,7 @@ func (s *SocialAzureAD) UserInfo(_ *http.Client, token *oauth2.Token) (*BasicUse
groups := extractGroups(claims) groups := extractGroups(claims)
if !s.IsGroupMember(groups) { if !s.IsGroupMember(groups) {
return nil, ErrMissingGroupMembership return nil, errMissingGroupMembership
} }
return &BasicUserInfo{ return &BasicUserInfo{

View File

@ -14,10 +14,10 @@ import (
) )
var ( var (
ErrMissingGroupMembership = &Error{"User not a member of one of the required groups"} errMissingGroupMembership = Error{"user not a member of one of the required groups"}
) )
type HttpGetResponse struct { type httpGetResponse struct {
Body []byte Body []byte
Headers http.Header Headers http.Header
} }
@ -44,20 +44,24 @@ func isEmailAllowed(email string, allowedDomains []string) bool {
return valid return valid
} }
func HttpGet(client *http.Client, url string) (response HttpGetResponse, err error) { func (s *SocialBase) httpGet(client *http.Client, url string) (response httpGetResponse, err error) {
r, err := client.Get(url) r, err := client.Get(url)
if err != nil { if err != nil {
return return
} }
defer r.Body.Close() defer func() {
if err := r.Body.Close(); err != nil {
s.log.Warn("Failed to close response body", "err", err)
}
}()
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
return return
} }
response = HttpGetResponse{body, r.Header} response = httpGetResponse{body, r.Header}
if r.StatusCode >= 300 { if r.StatusCode >= 300 {
err = fmt.Errorf(string(response.Body)) err = fmt.Errorf(string(response.Body))

View File

@ -229,7 +229,11 @@ func (s *SocialGenericOAuth) extractFromToken(token *oauth2.Token) *UserInfoJson
s.log.Error("Error creating zlib reader", "error", err) s.log.Error("Error creating zlib reader", "error", err)
return nil return nil
} }
defer fr.Close() defer func() {
if err := fr.Close(); err != nil {
s.log.Warn("Failed closing zlib reader", "error", err)
}
}()
rawJSON, err = ioutil.ReadAll(fr) rawJSON, err = ioutil.ReadAll(fr)
if err != nil { if err != nil {
s.log.Error("Error decompressing payload", "error", err) s.log.Error("Error decompressing payload", "error", err)
@ -251,7 +255,7 @@ func (s *SocialGenericOAuth) extractFromToken(token *oauth2.Token) *UserInfoJson
func (s *SocialGenericOAuth) extractFromAPI(client *http.Client) *UserInfoJson { func (s *SocialGenericOAuth) extractFromAPI(client *http.Client) *UserInfoJson {
s.log.Debug("Getting user info from API") s.log.Debug("Getting user info from API")
rawUserInfoResponse, err := HttpGet(client, s.apiUrl) rawUserInfoResponse, err := s.httpGet(client, s.apiUrl)
if err != nil { if err != nil {
s.log.Debug("Error getting user info from API", "url", s.apiUrl, "error", err) s.log.Debug("Error getting user info from API", "url", s.apiUrl, "error", err)
return nil return nil
@ -347,7 +351,7 @@ func (s *SocialGenericOAuth) FetchPrivateEmail(client *http.Client) (string, err
IsConfirmed bool `json:"is_confirmed"` IsConfirmed bool `json:"is_confirmed"`
} }
response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/emails")) response, err := s.httpGet(client, fmt.Sprintf(s.apiUrl+"/emails"))
if err != nil { if err != nil {
s.log.Error("Error getting email address", "url", s.apiUrl+"/emails", "error", err) s.log.Error("Error getting email address", "url", s.apiUrl+"/emails", "error", err)
return "", errutil.Wrap("Error getting email address", err) return "", errutil.Wrap("Error getting email address", err)
@ -390,7 +394,7 @@ func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, b
Id int `json:"id"` Id int `json:"id"`
} }
response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/teams")) response, err := s.httpGet(client, fmt.Sprintf(s.apiUrl+"/teams"))
if err != nil { if err != nil {
s.log.Error("Error getting team memberships", "url", s.apiUrl+"/teams", "error", err) s.log.Error("Error getting team memberships", "url", s.apiUrl+"/teams", "error", err)
return nil, false return nil, false
@ -419,7 +423,7 @@ func (s *SocialGenericOAuth) FetchOrganizations(client *http.Client) ([]string,
Login string `json:"login"` Login string `json:"login"`
} }
response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/orgs")) response, err := s.httpGet(client, fmt.Sprintf(s.apiUrl+"/orgs"))
if err != nil { if err != nil {
s.log.Error("Error getting organizations", "url", s.apiUrl+"/orgs", "error", err) s.log.Error("Error getting organizations", "url", s.apiUrl+"/orgs", "error", err)
return nil, false return nil, false

View File

@ -29,8 +29,8 @@ type GithubTeam struct {
} }
var ( var (
ErrMissingTeamMembership = &Error{"User not a member of one of the required teams"} ErrMissingTeamMembership = Error{"user not a member of one of the required teams"}
ErrMissingOrganizationMembership = &Error{"User not a member of one of the required organizations"} ErrMissingOrganizationMembership = Error{"user not a member of one of the required organizations"}
) )
func (s *SocialGithub) Type() int { func (s *SocialGithub) Type() int {
@ -86,7 +86,7 @@ func (s *SocialGithub) FetchPrivateEmail(client *http.Client) (string, error) {
Verified bool `json:"verified"` Verified bool `json:"verified"`
} }
response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/emails")) response, err := s.httpGet(client, fmt.Sprintf(s.apiUrl+"/emails"))
if err != nil { if err != nil {
return "", fmt.Errorf("Error getting email address: %s", err) return "", fmt.Errorf("Error getting email address: %s", err)
} }
@ -114,7 +114,7 @@ func (s *SocialGithub) FetchTeamMemberships(client *http.Client) ([]GithubTeam,
teams := make([]GithubTeam, 0) teams := make([]GithubTeam, 0)
for hasMore { for hasMore {
response, err := HttpGet(client, url) response, err := s.httpGet(client, url)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting team memberships: %s", err) return nil, fmt.Errorf("Error getting team memberships: %s", err)
} }
@ -157,16 +157,16 @@ func (s *SocialGithub) FetchOrganizations(client *http.Client, organizationsUrl
Login string `json:"login"` Login string `json:"login"`
} }
response, err := HttpGet(client, organizationsUrl) response, err := s.httpGet(client, organizationsUrl)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting organizations: %s", err) return nil, fmt.Errorf("error getting organizations: %s", err)
} }
var records []Record var records []Record
err = json.Unmarshal(response.Body, &records) err = json.Unmarshal(response.Body, &records)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting organizations: %s", err) return nil, fmt.Errorf("error getting organizations: %s", err)
} }
var logins = make([]string, len(records)) var logins = make([]string, len(records))
@ -184,9 +184,9 @@ func (s *SocialGithub) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
Email string `json:"email"` Email string `json:"email"`
} }
response, err := HttpGet(client, s.apiUrl) response, err := s.httpGet(client, s.apiUrl)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting user info: %s", err) return nil, fmt.Errorf("error getting user info: %s", err)
} }
err = json.Unmarshal(response.Body, &data) err = json.Unmarshal(response.Body, &data)

View File

@ -62,7 +62,7 @@ func (s *SocialGitlab) GetGroupsPage(client *http.Client, url string) ([]string,
return nil, next return nil, next
} }
response, err := HttpGet(client, url) response, err := s.httpGet(client, url)
if err != nil { if err != nil {
s.log.Error("Error getting groups from GitLab API", "err", err) s.log.Error("Error getting groups from GitLab API", "err", err)
return nil, next return nil, next
@ -98,7 +98,7 @@ func (s *SocialGitlab) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
State string State string
} }
response, err := HttpGet(client, s.apiUrl+"/user") response, err := s.httpGet(client, s.apiUrl+"/user")
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting user info: %s", err) return nil, fmt.Errorf("Error getting user info: %s", err)
} }
@ -123,7 +123,7 @@ func (s *SocialGitlab) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
} }
if !s.IsGroupMember(groups) { if !s.IsGroupMember(groups) {
return nil, ErrMissingGroupMembership return nil, errMissingGroupMembership
} }
return userInfo, nil return userInfo, nil

View File

@ -27,7 +27,7 @@ func (s *SocialGoogle) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
Email string `json:"email"` Email string `json:"email"`
} }
response, err := HttpGet(client, s.apiUrl) response, err := s.httpGet(client, s.apiUrl)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting user info: %s", err) return nil, fmt.Errorf("Error getting user info: %s", err)
} }

View File

@ -54,7 +54,7 @@ func (s *SocialGrafanaCom) UserInfo(client *http.Client, token *oauth2.Token) (*
Orgs []OrgRecord `json:"orgs"` Orgs []OrgRecord `json:"orgs"`
} }
response, err := HttpGet(client, s.url+"/api/oauth2/user") response, err := s.httpGet(client, s.url+"/api/oauth2/user")
if err != nil { if err != nil {
return nil, fmt.Errorf("Error getting user info: %s", err) return nil, fmt.Errorf("Error getting user info: %s", err)
} }

View File

@ -84,7 +84,7 @@ func (s *SocialOkta) UserInfo(client *http.Client, token *oauth2.Token) (*BasicU
groups := s.GetGroups(&data) groups := s.GetGroups(&data)
if !s.IsGroupMember(groups) { if !s.IsGroupMember(groups) {
return nil, ErrMissingGroupMembership return nil, errMissingGroupMembership
} }
return &BasicUserInfo{ return &BasicUserInfo{
@ -98,7 +98,7 @@ func (s *SocialOkta) UserInfo(client *http.Client, token *oauth2.Token) (*BasicU
} }
func (s *SocialOkta) extractAPI(data *OktaUserInfoJson, client *http.Client) error { func (s *SocialOkta) extractAPI(data *OktaUserInfoJson, client *http.Client) error {
rawUserInfoResponse, err := HttpGet(client, s.apiUrl) rawUserInfoResponse, err := s.httpGet(client, s.apiUrl)
if err != nil { if err != nil {
s.log.Debug("Error getting user info response", "url", s.apiUrl, "error", err) s.log.Debug("Error getting user info response", "url", s.apiUrl, "error", err)
return errutil.Wrapf(err, "error getting user info response") return errutil.Wrapf(err, "error getting user info response")

View File

@ -54,7 +54,7 @@ type Error struct {
s string s string
} }
func (e *Error) Error() string { func (e Error) Error() string {
return e.s return e.s
} }

View File

@ -35,8 +35,12 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec() sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
assert.Equal(t, 301, sc.resp.Code) assert.Equal(t, 301, sc.resp.Code)
// nolint:bodyclose
resp := sc.resp.Result() resp := sc.resp.Result()
resp.Body.Close() t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
redirectURL, err := resp.Location() redirectURL, err := resp.Location()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug), redirectURL.Path) assert.Equal(t, models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug), redirectURL.Path)
@ -54,8 +58,12 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec() sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
assert.Equal(t, 301, sc.resp.Code) assert.Equal(t, 301, sc.resp.Code)
// nolint:bodyclose
resp := sc.resp.Result() resp := sc.resp.Result()
resp.Body.Close() t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
redirectURL, err := resp.Location() redirectURL, err := resp.Location()
require.NoError(t, err) require.NoError(t, err)
expectedURL := models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug) expectedURL := models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)
@ -71,8 +79,12 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
sc.fakeReqWithParams("GET", "/d/asd/dash?orgId=1&panelId=12&fullscreen&edit", map[string]string{}).exec() sc.fakeReqWithParams("GET", "/d/asd/dash?orgId=1&panelId=12&fullscreen&edit", map[string]string{}).exec()
assert.Equal(t, 301, sc.resp.Code) assert.Equal(t, 301, sc.resp.Code)
// nolint:bodyclose
resp := sc.resp.Result() resp := sc.resp.Result()
resp.Body.Close() t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
redirectURL, err := resp.Location() redirectURL, err := resp.Location()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "/d/asd/d/asd/dash?editPanel=12&orgId=1", redirectURL.String()) assert.Equal(t, "/d/asd/d/asd/dash?editPanel=12&orgId=1", redirectURL.String())

View File

@ -378,8 +378,10 @@ func TestMiddlewareContext(t *testing.T) {
return nil return nil
}) })
key := fmt.Sprintf(authproxy.CachePrefix, authproxy.HashCacheKey(hdrName+"-"+group)) h, err := authproxy.HashCacheKey(hdrName + "-" + group)
err := sc.remoteCacheService.Set(key, userID, 0) require.NoError(t, err)
key := fmt.Sprintf(authproxy.CachePrefix, h)
err = sc.remoteCacheService.Set(key, userID, 0)
require.NoError(t, err) require.NoError(t, err)
sc.fakeReq("GET", "/") sc.fakeReq("GET", "/")

View File

@ -9,6 +9,7 @@ import (
"time" "time"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/securejsondata" "github.com/grafana/grafana/pkg/components/securejsondata"
@ -223,15 +224,16 @@ func TestDataSourceProxyCache(t *testing.T) {
// 2. Get HTTP transport from datasource which uses the test server as backend // 2. Get HTTP transport from datasource which uses the test server as backend
ds.Url = backend.URL ds.Url = backend.URL
transport, err := ds.GetHttpTransport() transport, err := ds.GetHttpTransport()
if err != nil { So(err, ShouldBeNil)
log.Fatal(err.Error())
}
// 3. Send test request which should have the Authorization header set // 3. Send test request which should have the Authorization header set
req := httptest.NewRequest("GET", backend.URL+"/test-headers", nil) req := httptest.NewRequest("GET", backend.URL+"/test-headers", nil)
res, err := transport.RoundTrip(req) res, err := transport.RoundTrip(req)
So(err, ShouldBeNil) So(err, ShouldBeNil)
defer res.Body.Close() t.Cleanup(func() {
err := res.Body.Close()
assert.NoError(t, err)
})
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
So(err, ShouldBeNil) So(err, ShouldBeNil)
bodyStr := string(body) bodyStr := string(body)

View File

@ -31,7 +31,10 @@ var handshake = goplugin.HandshakeConfig{
MagicCookieValue: grpcplugin.MagicCookieValue, MagicCookieValue: grpcplugin.MagicCookieValue,
} }
func newClientConfig(executablePath string, env []string, logger log.Logger, versionedPlugins map[int]goplugin.PluginSet) *goplugin.ClientConfig { func newClientConfig(executablePath string, env []string, logger log.Logger,
versionedPlugins map[int]goplugin.PluginSet) *goplugin.ClientConfig {
// We can ignore gosec G201 here, since the dynamic part of executablePath comes from the plugin definition
// nolint:gosec
cmd := exec.Command(executablePath) cmd := exec.Command(executablePath)
cmd.Env = env cmd.Env = env
@ -77,7 +80,7 @@ func getV2PluginSet() goplugin.PluginSet {
// NewBackendPlugin creates a new backend plugin factory used for registering a backend plugin. // NewBackendPlugin creates a new backend plugin factory used for registering a backend plugin.
func NewBackendPlugin(pluginID, executablePath string, startFns PluginStartFuncs) backendplugin.PluginFactoryFunc { func NewBackendPlugin(pluginID, executablePath string, startFns PluginStartFuncs) backendplugin.PluginFactoryFunc {
return New(PluginDescriptor{ return newPlugin(PluginDescriptor{
pluginID: pluginID, pluginID: pluginID,
executablePath: executablePath, executablePath: executablePath,
managed: true, managed: true,
@ -93,7 +96,7 @@ func NewBackendPlugin(pluginID, executablePath string, startFns PluginStartFuncs
// NewRendererPlugin creates a new renderer plugin factory used for registering a backend renderer plugin. // NewRendererPlugin creates a new renderer plugin factory used for registering a backend renderer plugin.
func NewRendererPlugin(pluginID, executablePath string, startFns PluginStartFuncs) backendplugin.PluginFactoryFunc { func NewRendererPlugin(pluginID, executablePath string, startFns PluginStartFuncs) backendplugin.PluginFactoryFunc {
return New(PluginDescriptor{ return newPlugin(PluginDescriptor{
pluginID: pluginID, pluginID: pluginID,
executablePath: executablePath, executablePath: executablePath,
managed: false, managed: false,

View File

@ -26,8 +26,8 @@ type grpcPlugin struct {
mutex sync.RWMutex mutex sync.RWMutex
} }
// New allocates and returns a new gRPC (external) backendplugin.Plugin. // newPlugin allocates and returns a new gRPC (external) backendplugin.Plugin.
func New(descriptor PluginDescriptor) backendplugin.PluginFactoryFunc { func newPlugin(descriptor PluginDescriptor) backendplugin.PluginFactoryFunc {
return backendplugin.PluginFactoryFunc(func(pluginID string, logger log.Logger, env []string) (backendplugin.Plugin, error) { return backendplugin.PluginFactoryFunc(func(pluginID string, logger log.Logger, env []string) (backendplugin.Plugin, error) {
return &grpcPlugin{ return &grpcPlugin{
descriptor: descriptor, descriptor: descriptor,

View File

@ -257,6 +257,11 @@ func (m *manager) callResourceInternal(w http.ResponseWriter, req *http.Request,
childCtx, cancel := context.WithCancel(req.Context()) childCtx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
stream := newCallResourceResponseStream(childCtx) stream := newCallResourceResponseStream(childCtx)
defer func() {
if err := stream.Close(); err != nil {
m.logger.Warn("Failed to close stream", "err", err)
}
}()
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
var flushStreamErr error var flushStreamErr error
@ -265,12 +270,15 @@ func (m *manager) callResourceInternal(w http.ResponseWriter, req *http.Request,
wg.Done() wg.Done()
}() }()
innerErr := p.CallResource(req.Context(), crReq, stream) if err := p.CallResource(req.Context(), crReq, stream); err != nil {
stream.Close() return err
if innerErr != nil {
return innerErr
} }
if err := stream.Close(); err != nil {
return err
}
wg.Wait() wg.Wait()
return flushStreamErr return flushStreamErr
}) })
} }

View File

@ -95,11 +95,11 @@ func loadPluginDashboard(pluginId, path string) (*models.Dashboard, error) {
return nil, PluginNotFoundError{pluginId} return nil, PluginNotFoundError{pluginId}
} }
dashboardFilePath := filepath.Join(plugin.PluginDir, path)
// nolint:gosec // nolint:gosec
// We can ignore the gosec G304 warning on this one because `plugin.PluginDir` is based // We can ignore the gosec G304 warning on this one because `plugin.PluginDir` is based
// on plugin folder structure on disk and not user input. `path` comes from the // on plugin folder structure on disk and not user input. `path` comes from the
// `plugin.json` configuration file for the loaded plugin // `plugin.json` configuration file for the loaded plugin
dashboardFilePath := filepath.Join(plugin.PluginDir, path)
reader, err := os.Open(dashboardFilePath) reader, err := os.Open(dashboardFilePath)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -335,9 +335,6 @@ func (s *PluginScanner) walker(currentPath string, f os.FileInfo, err error) err
return nil return nil
} }
// nolint:gosec
// We can ignore the gosec G304 warning on this one because `currentPath` is based
// on plugin the folder structure on disk and not user input.
if err := s.loadPlugin(currentPath); err != nil { if err := s.loadPlugin(currentPath); err != nil {
s.log.Error("Failed to load plugin", "error", err, "pluginPath", filepath.Dir(currentPath)) s.log.Error("Failed to load plugin", "error", err, "pluginPath", filepath.Dir(currentPath))
s.errors = append(s.errors, err) s.errors = append(s.errors, err)
@ -349,6 +346,9 @@ func (s *PluginScanner) walker(currentPath string, f os.FileInfo, err error) err
func (s *PluginScanner) loadPlugin(pluginJSONFilePath string) error { func (s *PluginScanner) loadPlugin(pluginJSONFilePath string) error {
s.log.Debug("Loading plugin", "path", pluginJSONFilePath) s.log.Debug("Loading plugin", "path", pluginJSONFilePath)
currentDir := filepath.Dir(pluginJSONFilePath) currentDir := filepath.Dir(pluginJSONFilePath)
// nolint:gosec
// We can ignore the gosec G304 warning on this one because `currentPath` is based
// on plugin the folder structure on disk and not user input.
reader, err := os.Open(pluginJSONFilePath) reader, err := os.Open(pluginJSONFilePath)
if err != nil { if err != nil {
return err return err

View File

@ -48,13 +48,15 @@ func (pm *PluginManager) checkForUpdates() {
pluginSlugs := getAllExternalPluginSlugs() pluginSlugs := getAllExternalPluginSlugs()
resp, err := httpClient.Get("https://grafana.com/api/plugins/versioncheck?slugIn=" + pluginSlugs + "&grafanaVersion=" + setting.BuildVersion) resp, err := httpClient.Get("https://grafana.com/api/plugins/versioncheck?slugIn=" + pluginSlugs + "&grafanaVersion=" + setting.BuildVersion)
if err != nil { if err != nil {
log.Tracef("Failed to get plugins repo from grafana.com, %v", err.Error()) log.Tracef("Failed to get plugins repo from grafana.com, %v", err.Error())
return return
} }
defer func() {
defer resp.Body.Close() if err := resp.Body.Close(); err != nil {
log.Warn("Failed to close response body", "err", err)
}
}()
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
@ -91,8 +93,11 @@ func (pm *PluginManager) checkForUpdates() {
log.Tracef("Failed to get latest.json repo from github.com: %v", err.Error()) log.Tracef("Failed to get latest.json repo from github.com: %v", err.Error())
return return
} }
defer func() {
defer resp2.Body.Close() if err := resp2.Body.Close(); err != nil {
pm.log.Warn("Failed to close response body", "err", err)
}
}()
body, err = ioutil.ReadAll(resp2.Body) body, err = ioutil.ReadAll(resp2.Body)
if err != nil { if err != nil {
log.Tracef("Update check failed, reading response from github.com, %v", err.Error()) log.Tracef("Update check failed, reading response from github.com, %v", err.Error())

View File

@ -341,7 +341,11 @@ func (s *Server) notifySystemd(state string) {
s.log.Warn("Failed to connect to systemd", "err", err, "socket", notifySocket) s.log.Warn("Failed to connect to systemd", "err", err, "socket", notifySocket)
return return
} }
defer conn.Close() defer func() {
if err := conn.Close(); err != nil {
s.log.Warn("Failed to close connection", "err", err)
}
}()
_, err = conn.Write([]byte(state)) _, err = conn.Write([]byte(state))
if err != nil { if err != nil {

View File

@ -19,10 +19,13 @@ func TestAlertingUsageStats(t *testing.T) {
ae.Bus.AddHandler(func(query *models.GetAllAlertsQuery) error { ae.Bus.AddHandler(func(query *models.GetAllAlertsQuery) error {
var createFake = func(file string) *simplejson.Json { var createFake = func(file string) *simplejson.Json {
// Ignore gosec warning G304 since it's a test
// nolint:gosec
content, err := ioutil.ReadFile(file) content, err := ioutil.ReadFile(file)
require.NoError(t, err, "expected to be able to read file") require.NoError(t, err, "expected to be able to read file")
j, _ := simplejson.NewJson(content) j, err := simplejson.NewJson(content)
require.NoError(t, err)
return j return j
} }

View File

@ -387,8 +387,10 @@ func (pn *PushoverNotifier) genPushoverBody(evalContext *alerting.EvalContext, m
if err != nil { if err != nil {
return nil, b, err return nil, b, err
} }
if err := w.Close(); err != nil {
return nil, b, err
}
w.Close()
headers := map[string]string{ headers := map[string]string{
"Content-Type": w.FormDataContentType(), "Content-Type": w.FormDataContentType(),
} }

View File

@ -170,6 +170,11 @@ func (tn *TelegramNotifier) buildMessageInlineImage(evalContext *alerting.EvalCo
func (tn *TelegramNotifier) generateTelegramCmd(message string, messageField string, apiAction string, extraConf func(writer *multipart.Writer)) (*models.SendWebhookSync, error) { func (tn *TelegramNotifier) generateTelegramCmd(message string, messageField string, apiAction string, extraConf func(writer *multipart.Writer)) (*models.SendWebhookSync, error) {
var body bytes.Buffer var body bytes.Buffer
w := multipart.NewWriter(&body) w := multipart.NewWriter(&body)
defer func() {
if err := w.Close(); err != nil {
tn.log.Warn("Failed to close writer", "err", err)
}
}()
fw, err := w.CreateFormField("chat_id") fw, err := w.CreateFormField("chat_id")
if err != nil { if err != nil {
@ -189,7 +194,9 @@ func (tn *TelegramNotifier) generateTelegramCmd(message string, messageField str
extraConf(w) extraConf(w)
w.Close() if err := w.Close(); err != nil {
return nil, err
}
tn.log.Info("Sending telegram notification", "chat_id", tn.ChatID, "bot_token", tn.BotToken, "apiAction", apiAction) tn.log.Info("Sending telegram notification", "chat_id", tn.ChatID, "bot_token", tn.BotToken, "apiAction", apiAction)
url := fmt.Sprintf(telegramAPIURL, tn.BotToken, apiAction) url := fmt.Sprintf(telegramAPIURL, tn.BotToken, apiAction)

View File

@ -65,7 +65,9 @@ func TestInitContextWithAuthProxy_CachedInvalidUserID(t *testing.T) {
Logger: log.New("Test"), Logger: log.New("Test"),
} }
req.Header.Set(svc.Cfg.AuthProxyHeaderName, name) req.Header.Set(svc.Cfg.AuthProxyHeaderName, name)
key := fmt.Sprintf(authproxy.CachePrefix, authproxy.HashCacheKey(name)) h, err := authproxy.HashCacheKey(name)
require.NoError(t, err)
key := fmt.Sprintf(authproxy.CachePrefix, h)
t.Logf("Injecting stale user ID in cache with key %q", key) t.Logf("Injecting stale user ID in cache with key %q", key)
err = svc.RemoteCache.Set(key, int64(33), 0) err = svc.RemoteCache.Set(key, int64(33), 0)

View File

@ -141,25 +141,29 @@ func (auth *AuthProxy) IsAllowedIP() error {
)) ))
} }
func HashCacheKey(key string) string { func HashCacheKey(key string) (string, error) {
hasher := fnv.New128a() hasher := fnv.New128a()
// according to the documentation, Hash.Write cannot error, but linter is complaining if _, err := hasher.Write([]byte(key)); err != nil {
hasher.Write([]byte(key)) // nolint: errcheck return "", err
return hex.EncodeToString(hasher.Sum(nil)) }
return hex.EncodeToString(hasher.Sum(nil)), nil
} }
// getKey forms a key for the cache based on the headers received as part of the authentication flow. // getKey forms a key for the cache based on the headers received as part of the authentication flow.
// Our configuration supports multiple headers. The main header contains the email or username. // Our configuration supports multiple headers. The main header contains the email or username.
// And the additional ones that allow us to specify extra attributes: Name, Email or Groups. // And the additional ones that allow us to specify extra attributes: Name, Email or Groups.
func (auth *AuthProxy) getKey() string { func (auth *AuthProxy) getKey() (string, error) {
key := strings.TrimSpace(auth.header) // start the key with the main header key := strings.TrimSpace(auth.header) // start the key with the main header
auth.headersIterator(func(_, header string) { auth.headersIterator(func(_, header string) {
key = strings.Join([]string{key, header}, "-") // compose the key with any additional headers key = strings.Join([]string{key, header}, "-") // compose the key with any additional headers
}) })
hashedKey := HashCacheKey(key) hashedKey, err := HashCacheKey(key)
return fmt.Sprintf(CachePrefix, hashedKey) if err != nil {
return "", err
}
return fmt.Sprintf(CachePrefix, hashedKey), nil
} }
// Login logs in user ID by whatever means possible. // Login logs in user ID by whatever means possible.
@ -194,7 +198,10 @@ func (auth *AuthProxy) Login(logger log.Logger, ignoreCache bool) (int64, error)
// GetUserViaCache gets user ID from cache. // GetUserViaCache gets user ID from cache.
func (auth *AuthProxy) GetUserViaCache(logger log.Logger) (int64, error) { func (auth *AuthProxy) GetUserViaCache(logger log.Logger) (int64, error) {
cacheKey := auth.getKey() cacheKey, err := auth.getKey()
if err != nil {
return 0, err
}
logger.Debug("Getting user ID via auth cache", "cacheKey", cacheKey) logger.Debug("Getting user ID via auth cache", "cacheKey", cacheKey)
userID, err := auth.remoteCache.Get(cacheKey) userID, err := auth.remoteCache.Get(cacheKey)
if err != nil { if err != nil {
@ -208,7 +215,10 @@ func (auth *AuthProxy) GetUserViaCache(logger log.Logger) (int64, error) {
// RemoveUserFromCache removes user from cache. // RemoveUserFromCache removes user from cache.
func (auth *AuthProxy) RemoveUserFromCache(logger log.Logger) error { func (auth *AuthProxy) RemoveUserFromCache(logger log.Logger) error {
cacheKey := auth.getKey() cacheKey, err := auth.getKey()
if err != nil {
return err
}
logger.Debug("Removing user from auth cache", "cacheKey", cacheKey) logger.Debug("Removing user from auth cache", "cacheKey", cacheKey)
if err := auth.remoteCache.Delete(cacheKey); err != nil { if err := auth.remoteCache.Delete(cacheKey); err != nil {
return err return err
@ -318,18 +328,20 @@ func (auth *AuthProxy) GetSignedInUser(userID int64) (*models.SignedInUser, erro
// Remember user in cache // Remember user in cache
func (auth *AuthProxy) Remember(id int64) error { func (auth *AuthProxy) Remember(id int64) error {
key := auth.getKey() key, err := auth.getKey()
if err != nil {
return err
}
// Check if user already in cache // Check if user already in cache
userID, _ := auth.remoteCache.Get(key) userID, err := auth.remoteCache.Get(key)
if userID != nil { if err == nil && userID != nil {
return nil return nil
} }
expiration := time.Duration(auth.cfg.AuthProxySyncTTL) * time.Minute expiration := time.Duration(auth.cfg.AuthProxySyncTTL) * time.Minute
err := auth.remoteCache.Set(key, id, expiration) if err := auth.remoteCache.Set(key, id, expiration); err != nil {
if err != nil {
return err return err
} }

View File

@ -87,12 +87,16 @@ func TestMiddlewareContext(t *testing.T) {
t.Run("When the cache only contains the main header with a simple cache key", func(t *testing.T) { t.Run("When the cache only contains the main header with a simple cache key", func(t *testing.T) {
const id int64 = 33 const id int64 = 33
// Set cache key // Set cache key
key := fmt.Sprintf(CachePrefix, HashCacheKey(hdrName)) h, err := HashCacheKey(hdrName)
err := cache.Set(key, id, 0) require.NoError(t, err)
key := fmt.Sprintf(CachePrefix, h)
err = cache.Set(key, id, 0)
require.NoError(t, err) require.NoError(t, err)
// Set up the middleware // Set up the middleware
auth := prepareMiddleware(t, cache, nil) auth := prepareMiddleware(t, cache, nil)
assert.Equal(t, key, auth.getKey()) gotKey, err := auth.getKey()
require.NoError(t, err)
assert.Equal(t, key, gotKey)
gotID, err := auth.Login(logger, false) gotID, err := auth.Login(logger, false)
require.NoError(t, err) require.NoError(t, err)
@ -104,15 +108,17 @@ func TestMiddlewareContext(t *testing.T) {
const id int64 = 33 const id int64 = 33
const group = "grafana-core-team" const group = "grafana-core-team"
key := fmt.Sprintf(CachePrefix, HashCacheKey(hdrName+"-"+group)) h, err := HashCacheKey(hdrName + "-" + group)
err := cache.Set(key, id, 0) require.NoError(t, err)
key := fmt.Sprintf(CachePrefix, h)
err = cache.Set(key, id, 0)
require.NoError(t, err) require.NoError(t, err)
auth := prepareMiddleware(t, cache, func(req *http.Request, cfg *setting.Cfg) { auth := prepareMiddleware(t, cache, func(req *http.Request, cfg *setting.Cfg) {
req.Header.Set("X-WEBAUTH-GROUPS", group) req.Header.Set("X-WEBAUTH-GROUPS", group)
cfg.AuthProxyHeaders = map[string]string{"Groups": "X-WEBAUTH-GROUPS"} cfg.AuthProxyHeaders = map[string]string{"Groups": "X-WEBAUTH-GROUPS"}
}) })
assert.Equal(t, "auth-proxy-sync-ttl:14f69b7023baa0ac98c96b31cec07bc0", auth.getKey()) assert.Equal(t, "auth-proxy-sync-ttl:14f69b7023baa0ac98c96b31cec07bc0", key)
gotID, err := auth.Login(logger, false) gotID, err := auth.Login(logger, false)
require.NoError(t, err) require.NoError(t, err)

View File

@ -64,8 +64,12 @@ func TestTokenRotationAtEndOfRequest(t *testing.T) {
ctxHdlr.rotateEndOfRequestFunc(reqContext, uts, token)(reqContext.Resp) ctxHdlr.rotateEndOfRequestFunc(reqContext, uts, token)(reqContext.Resp)
foundLoginCookie := false foundLoginCookie := false
// nolint:bodyclose
resp := rr.Result() resp := rr.Result()
defer resp.Body.Close() t.Cleanup(func() {
err := resp.Body.Close()
assert.NoError(t, err)
})
for _, c := range resp.Cookies() { for _, c := range resp.Cookies() {
if c.Name == "login_token" { if c.Name == "login_token" {
foundLoginCookie = true foundLoginCookie = true

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestReadingLDAPSettings(t *testing.T) { func TestReadingLDAPSettings(t *testing.T) {
@ -14,9 +15,10 @@ func TestReadingLDAPSettings(t *testing.T) {
} }
func TestReadingLDAPSettingsWithEnvVariable(t *testing.T) { func TestReadingLDAPSettingsWithEnvVariable(t *testing.T) {
os.Setenv("ENV_PASSWORD", "MySecret") err := os.Setenv("ENV_PASSWORD", "MySecret")
require.NoError(t, err)
config, err := readConfig("testdata/ldap.toml") config, err := readConfig("testdata/ldap.toml")
assert.Nil(t, err, "No error when reading ldap config") require.NoError(t, err)
assert.EqualValues(t, "MySecret", config.Servers[0].BindPassword) assert.EqualValues(t, "MySecret", config.Servers[0].BindPassword)
} }

View File

@ -76,8 +76,11 @@ func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook *
if err != nil { if err != nil {
return err return err
} }
defer func() {
defer resp.Body.Close() if err := resp.Body.Close(); err != nil {
ns.log.Warn("Failed to close response body", "err", err)
}
}()
if resp.StatusCode/100 == 2 { if resp.StatusCode/100 == 2 {
ns.log.Debug("Webhook succeeded", "url", webhook.Url, "statuscode", resp.Status) ns.log.Debug("Webhook succeeded", "url", webhook.Url, "statuscode", resp.Status)

View File

@ -19,10 +19,14 @@ import (
func TestValues(t *testing.T) { func TestValues(t *testing.T) {
Convey("Values", t, func() { Convey("Values", t, func() {
os.Setenv("INT", "1") err := os.Setenv("INT", "1")
os.Setenv("STRING", "test") So(err, ShouldBeNil)
os.Setenv("EMPTYSTRING", "") err = os.Setenv("STRING", "test")
os.Setenv("BOOL", "true") So(err, ShouldBeNil)
err = os.Setenv("EMPTYSTRING", "")
So(err, ShouldBeNil)
err = os.Setenv("BOOL", "true")
So(err, ShouldBeNil)
Convey("IntValue", func() { Convey("IntValue", func() {
type Data struct { type Data struct {
@ -240,10 +244,14 @@ func TestValues(t *testing.T) {
}) })
Reset(func() { Reset(func() {
os.Unsetenv("INT") err := os.Unsetenv("INT")
os.Unsetenv("STRING") So(err, ShouldBeNil)
os.Unsetenv("EMPTYSTRING") err = os.Unsetenv("STRING")
os.Unsetenv("BOOL") So(err, ShouldBeNil)
err = os.Unsetenv("EMPTYSTRING")
So(err, ShouldBeNil)
err = os.Unsetenv("BOOL")
So(err, ShouldBeNil)
}) })
}) })
} }

View File

@ -77,7 +77,11 @@ func (rs *RenderingService) renderViaHttp(ctx context.Context, renderKey string,
} }
// save response to file // save response to file
defer resp.Body.Close() defer func() {
if err := resp.Body.Close(); err != nil {
rs.log.Warn("Failed to close response body", "err", err)
}
}()
// check for timeout first // check for timeout first
if errors.Is(reqContext.Err(), context.DeadlineExceeded) { if errors.Is(reqContext.Err(), context.DeadlineExceeded) {

View File

@ -15,8 +15,12 @@ func TestDynamicSettingsSupport_Override(t *testing.T) {
keyName := "bar" keyName := "bar"
expected := "dynamic value" expected := "dynamic value"
os.Setenv(envKey, expected) err := os.Setenv(envKey, expected)
defer func() { os.Unsetenv(envKey) }() require.NoError(t, err)
defer func() {
err := os.Unsetenv(envKey)
require.NoError(t, err)
}()
value := cfg.SectionWithEnvOverrides(sectionName).Key(keyName).MustString("default value") value := cfg.SectionWithEnvOverrides(sectionName).Key(keyName).MustString("default value")
require.Equal(t, expected, value) require.Equal(t, expected, value)

View File

@ -16,7 +16,8 @@ import (
func TestExpandVar_EnvSuccessful(t *testing.T) { func TestExpandVar_EnvSuccessful(t *testing.T) {
const key = "GF_TEST_SETTING_EXPANDER_ENV" const key = "GF_TEST_SETTING_EXPANDER_ENV"
const expected = "aurora borealis" const expected = "aurora borealis"
os.Setenv(key, expected) err := os.Setenv(key, expected)
require.NoError(t, err)
// expanded format // expanded format
{ {
@ -39,12 +40,14 @@ func TestExpandVar_FileSuccessful(t *testing.T) {
file := f.Name() file := f.Name()
defer func() { defer func() {
os.Remove(file) err := os.Remove(file)
require.NoError(t, err)
}() }()
_, err = f.WriteString("hello, world") _, err = f.WriteString("hello, world")
require.NoError(t, err) require.NoError(t, err)
f.Close() err = f.Close()
require.NoError(t, err)
got, err := ExpandVar(fmt.Sprintf("$__file{%s}", file)) got, err := ExpandVar(fmt.Sprintf("$__file{%s}", file))
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -39,7 +39,10 @@ func TestLoadingSettings(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("failed to load defaults.ini file: %v", err) t.Errorf("failed to load defaults.ini file: %v", err)
} }
defer file.Close() defer func() {
err := file.Close()
So(err, ShouldBeNil)
}()
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
for scanner.Scan() { for scanner.Scan() {
@ -51,10 +54,11 @@ func TestLoadingSettings(t *testing.T) {
}) })
Convey("Should be able to override via environment variables", func() { Convey("Should be able to override via environment variables", func() {
os.Setenv("GF_SECURITY_ADMIN_USER", "superduper") err := os.Setenv("GF_SECURITY_ADMIN_USER", "superduper")
require.NoError(t, err)
cfg := NewCfg() cfg := NewCfg()
err := cfg.Load(&CommandLineArgs{HomePath: "../../"}) err = cfg.Load(&CommandLineArgs{HomePath: "../../"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(AdminUser, ShouldEqual, "superduper") So(AdminUser, ShouldEqual, "superduper")
@ -63,29 +67,32 @@ func TestLoadingSettings(t *testing.T) {
}) })
Convey("Should replace password when defined in environment", func() { Convey("Should replace password when defined in environment", func() {
os.Setenv("GF_SECURITY_ADMIN_PASSWORD", "supersecret") err := os.Setenv("GF_SECURITY_ADMIN_PASSWORD", "supersecret")
require.NoError(t, err)
cfg := NewCfg() cfg := NewCfg()
err := cfg.Load(&CommandLineArgs{HomePath: "../../"}) err = cfg.Load(&CommandLineArgs{HomePath: "../../"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(appliedEnvOverrides, ShouldContain, "GF_SECURITY_ADMIN_PASSWORD=*********") So(appliedEnvOverrides, ShouldContain, "GF_SECURITY_ADMIN_PASSWORD=*********")
}) })
Convey("Should return an error when url is invalid", func() { Convey("Should return an error when url is invalid", func() {
os.Setenv("GF_DATABASE_URL", "postgres.%31://grafana:secret@postgres:5432/grafana") err := os.Setenv("GF_DATABASE_URL", "postgres.%31://grafana:secret@postgres:5432/grafana")
require.NoError(t, err)
cfg := NewCfg() cfg := NewCfg()
err := cfg.Load(&CommandLineArgs{HomePath: "../../"}) err = cfg.Load(&CommandLineArgs{HomePath: "../../"})
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("Should replace password in URL when url environment is defined", func() { Convey("Should replace password in URL when url environment is defined", func() {
os.Setenv("GF_DATABASE_URL", "mysql://user:secret@localhost:3306/database") err := os.Setenv("GF_DATABASE_URL", "mysql://user:secret@localhost:3306/database")
require.NoError(t, err)
cfg := NewCfg() cfg := NewCfg()
err := cfg.Load(&CommandLineArgs{HomePath: "../../"}) err = cfg.Load(&CommandLineArgs{HomePath: "../../"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(appliedEnvOverrides, ShouldContain, "GF_DATABASE_URL=mysql://user:-redacted-@localhost:3306/database") So(appliedEnvOverrides, ShouldContain, "GF_DATABASE_URL=mysql://user:-redacted-@localhost:3306/database")
@ -186,9 +193,10 @@ func TestLoadingSettings(t *testing.T) {
Convey("Can use environment variables in config values", func() { Convey("Can use environment variables in config values", func() {
if runtime.GOOS == windows { if runtime.GOOS == windows {
os.Setenv("GF_DATA_PATH", `c:\tmp\env_override`) err := os.Setenv("GF_DATA_PATH", `c:\tmp\env_override`)
require.NoError(t, err)
cfg := NewCfg() cfg := NewCfg()
err := cfg.Load(&CommandLineArgs{ err = cfg.Load(&CommandLineArgs{
HomePath: "../../", HomePath: "../../",
Args: []string{"cfg:paths.data=${GF_DATA_PATH}"}, Args: []string{"cfg:paths.data=${GF_DATA_PATH}"},
}) })
@ -196,9 +204,10 @@ func TestLoadingSettings(t *testing.T) {
So(cfg.DataPath, ShouldEqual, `c:\tmp\env_override`) So(cfg.DataPath, ShouldEqual, `c:\tmp\env_override`)
} else { } else {
os.Setenv("GF_DATA_PATH", "/tmp/env_override") err := os.Setenv("GF_DATA_PATH", "/tmp/env_override")
require.NoError(t, err)
cfg := NewCfg() cfg := NewCfg()
err := cfg.Load(&CommandLineArgs{ err = cfg.Load(&CommandLineArgs{
HomePath: "../../", HomePath: "../../",
Args: []string{"cfg:paths.data=${GF_DATA_PATH}"}, Args: []string{"cfg:paths.data=${GF_DATA_PATH}"},
}) })

View File

@ -172,7 +172,11 @@ func (e *ApplicationInsightsDatasource) executeQuery(ctx context.Context, query
} }
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close() defer func() {
if err := res.Body.Close(); err != nil {
azlog.Warn("Failed to close response body", "err", err)
}
}()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -156,8 +156,7 @@ func TestInsightsMetricsResultToFrame(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
res, err := loadInsightsMetricsResponse(tt.testFile) res := loadInsightsMetricsResponse(t, tt.testFile)
require.NoError(t, err)
frame, err := InsightsMetricsResultToFrame(res, tt.metric, tt.agg, tt.dimensions) frame, err := InsightsMetricsResultToFrame(res, tt.metric, tt.agg, tt.dimensions)
require.NoError(t, err) require.NoError(t, err)
@ -171,16 +170,23 @@ func TestInsightsMetricsResultToFrame(t *testing.T) {
} }
} }
func loadInsightsMetricsResponse(name string) (MetricsResult, error) { func loadInsightsMetricsResponse(t *testing.T, name string) MetricsResult {
var mr MetricsResult t.Helper()
path := filepath.Join("testdata", name) path := filepath.Join("testdata", name)
// Ignore gosec warning G304 since it's a test
// nolint:gosec
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { require.NoError(t, err)
return mr, err defer func() {
} err := f.Close()
defer f.Close() require.NoError(t, err)
}()
d := json.NewDecoder(f) d := json.NewDecoder(f)
var mr MetricsResult
err = d.Decode(&mr) err = d.Decode(&mr)
return mr, err require.NoError(t, err)
return mr
} }

View File

@ -264,11 +264,14 @@ func (ar *AzureLogAnalyticsResponse) GetPrimaryResultTable() (*AzureLogAnalytics
func (e *AzureLogAnalyticsDatasource) unmarshalResponse(res *http.Response) (AzureLogAnalyticsResponse, error) { func (e *AzureLogAnalyticsDatasource) unmarshalResponse(res *http.Response) (AzureLogAnalyticsResponse, error) {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
return AzureLogAnalyticsResponse{}, err return AzureLogAnalyticsResponse{}, err
} }
defer func() {
if err := res.Body.Close(); err != nil {
azlog.Warn("Failed to close response body", "err", err)
}
}()
if res.StatusCode/100 != 2 { if res.StatusCode/100 != 2 {
azlog.Debug("Request failed", "status", res.Status, "body", string(body)) azlog.Debug("Request failed", "status", res.Status, "body", string(body))

View File

@ -10,6 +10,7 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/xorcare/pointer" "github.com/xorcare/pointer"
) )
@ -140,8 +141,7 @@ func TestLogTableToFrame(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
res, err := loadLogAnalyticsTestFileWithNumber(tt.testFile) res := loadLogAnalyticsTestFileWithNumber(t, tt.testFile)
require.NoError(t, err)
frame, err := LogTableToFrame(&res.Tables[0]) frame, err := LogTableToFrame(&res.Tables[0])
require.NoError(t, err) require.NoError(t, err)
@ -152,17 +152,22 @@ func TestLogTableToFrame(t *testing.T) {
} }
} }
func loadLogAnalyticsTestFileWithNumber(name string) (AzureLogAnalyticsResponse, error) { func loadLogAnalyticsTestFileWithNumber(t *testing.T, name string) AzureLogAnalyticsResponse {
var data AzureLogAnalyticsResponse t.Helper()
path := filepath.Join("testdata", name) path := filepath.Join("testdata", name)
// Ignore gosec warning G304 since it's a test
// nolint:gosec
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { require.NoError(t, err)
return data, err defer func() {
} err := f.Close()
defer f.Close() assert.NoError(t, err)
}()
d := json.NewDecoder(f) d := json.NewDecoder(f)
d.UseNumber() d.UseNumber()
var data AzureLogAnalyticsResponse
err = d.Decode(&data) err = d.Decode(&data)
return data, err require.NoError(t, err)
return data
} }

View File

@ -206,6 +206,11 @@ func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureM
queryResult.Error = err queryResult.Error = err
return queryResult, AzureMonitorResponse{}, nil return queryResult, AzureMonitorResponse{}, nil
} }
defer func() {
if err := res.Body.Close(); err != nil {
azlog.Warn("Failed to close response body", "err", err)
}
}()
data, err := e.unmarshalResponse(res) data, err := e.unmarshalResponse(res)
if err != nil { if err != nil {
@ -256,7 +261,6 @@ func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo *mode
func (e *AzureMonitorDatasource) unmarshalResponse(res *http.Response) (AzureMonitorResponse, error) { func (e *AzureMonitorDatasource) unmarshalResponse(res *http.Response) (AzureMonitorResponse, error) {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
return AzureMonitorResponse{}, err return AzureMonitorResponse{}, err
} }

View File

@ -433,10 +433,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
azData, err := loadTestFile("azuremonitor/" + tt.responseFile) azData := loadTestFile(t, "azuremonitor/"+tt.responseFile)
require.NoError(t, err)
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"} res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
err = datasource.parseResponse(res, azData, tt.mockQuery) err := datasource.parseResponse(res, azData, tt.mockQuery)
require.NoError(t, err) require.NoError(t, err)
frames, err := res.Dataframes.Decoded() frames, err := res.Dataframes.Decoded()
@ -496,14 +495,17 @@ func TestFindClosestAllowIntervalMS(t *testing.T) {
} }
} }
func loadTestFile(name string) (AzureMonitorResponse, error) { func loadTestFile(t *testing.T, name string) AzureMonitorResponse {
var azData AzureMonitorResponse t.Helper()
path := filepath.Join("testdata", name) path := filepath.Join("testdata", name)
// Ignore gosec warning G304 since it's a test
// nolint:gosec
jsonBody, err := ioutil.ReadFile(path) jsonBody, err := ioutil.ReadFile(path)
if err != nil { require.NoError(t, err)
return azData, err
} var azData AzureMonitorResponse
err = json.Unmarshal(jsonBody, &azData) err = json.Unmarshal(jsonBody, &azData)
return azData, err require.NoError(t, err)
return azData
} }

View File

@ -132,10 +132,14 @@ func (e *InsightsAnalyticsDatasource) executeQuery(ctx context.Context, query *I
} }
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
return queryResultError(err) return queryResultError(err)
} }
defer func() {
if err := res.Body.Close(); err != nil {
azlog.Warn("Failed to close response body", "err", err)
}
}()
if res.StatusCode/100 != 2 { if res.StatusCode/100 != 2 {
azlog.Debug("Request failed", "status", res.Status, "body", string(body)) azlog.Debug("Request failed", "status", res.Status, "body", string(body))

View File

@ -482,10 +482,14 @@ func (e *CloudMonitoringExecutor) executeQuery(ctx context.Context, query *cloud
func (e *CloudMonitoringExecutor) unmarshalResponse(res *http.Response) (cloudMonitoringResponse, error) { func (e *CloudMonitoringExecutor) unmarshalResponse(res *http.Response) (cloudMonitoringResponse, error) {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
return cloudMonitoringResponse{}, err return cloudMonitoringResponse{}, err
} }
defer func() {
if err := res.Body.Close(); err != nil {
slog.Warn("Failed to close response body", "err", err)
}
}()
if res.StatusCode/100 != 2 { if res.StatusCode/100 != 2 {
slog.Error("Request failed", "status", res.Status, "body", string(body)) slog.Error("Request failed", "status", res.Status, "body", string(body))

View File

@ -989,6 +989,8 @@ func TestCloudMonitoring(t *testing.T) {
func loadTestFile(path string) (cloudMonitoringResponse, error) { func loadTestFile(path string) (cloudMonitoringResponse, error) {
var data cloudMonitoringResponse var data cloudMonitoringResponse
// Can ignore gosec warning G304 here since it's a test path
// nolint:gosec
jsonBody, err := ioutil.ReadFile(path) jsonBody, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return data, err return data, err

View File

@ -226,7 +226,11 @@ func (c *baseClientImpl) ExecuteMultisearch(r *MultiSearchRequest) (*MultiSearch
return nil, err return nil, err
} }
res := clientRes.httpResponse res := clientRes.httpResponse
defer res.Body.Close() defer func() {
if err := res.Body.Close(); err != nil {
clientLog.Warn("Failed to close response body", "err", err)
}
}()
clientLog.Debug("Received multisearch response", "code", res.StatusCode, "status", res.Status, "content-length", res.ContentLength) clientLog.Debug("Received multisearch response", "code", res.StatusCode, "status", res.Status, "content-length", res.ContentLength)

View File

@ -133,10 +133,14 @@ func (e *GraphiteExecutor) Query(ctx context.Context, dsInfo *models.DataSource,
func (e *GraphiteExecutor) parseResponse(res *http.Response) ([]TargetResponseDTO, error) { func (e *GraphiteExecutor) parseResponse(res *http.Response) ([]TargetResponseDTO, error) {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer func() {
if err := res.Body.Close(); err != nil {
glog.Warn("Failed to close response body", "err", err)
}
}()
if res.StatusCode/100 != 2 { if res.StatusCode/100 != 2 {
glog.Info("Request failed", "status", res.Status, "body", string(body)) glog.Info("Request failed", "status", res.Status, "body", string(body))

View File

@ -82,10 +82,13 @@ func (e *InfluxDBExecutor) Query(ctx context.Context, dsInfo *models.DataSource,
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer func() {
defer resp.Body.Close() if err := resp.Body.Close(); err != nil {
glog.Warn("Failed to close response body", "err", err)
}
}()
if resp.StatusCode/100 != 2 { if resp.StatusCode/100 != 2 {
return nil, fmt.Errorf("InfluxDB returned statuscode invalid status code: %s", resp.Status) return nil, fmt.Errorf("InfluxDB returned error status: %s", resp.Status)
} }
var response Response var response Response

View File

@ -110,10 +110,14 @@ func (e *OpenTsdbExecutor) parseResponse(query OpenTsdbQuery, res *http.Response
queryRes := tsdb.NewQueryResult() queryRes := tsdb.NewQueryResult()
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer func() {
if err := res.Body.Close(); err != nil {
plog.Warn("Failed to close response body", "err", err)
}
}()
if res.StatusCode/100 != 2 { if res.StatusCode/100 != 2 {
plog.Info("Request failed", "status", res.Status, "body", string(body)) plog.Info("Request failed", "status", res.Status, "body", string(body))

View File

@ -173,8 +173,11 @@ func (e *sqlQueryEndpoint) Query(ctx context.Context, dsInfo *models.DataSource,
queryResult.Error = e.queryResultTransformer.TransformQueryError(err) queryResult.Error = e.queryResultTransformer.TransformQueryError(err)
return return
} }
defer func() {
defer rows.Close() if err := rows.Close(); err != nil {
e.log.Warn("Failed to close rows", "err", err)
}
}()
format := query.Model.Get("format").MustString("time_series") format := query.Model.Get("format").MustString("time_series")

View File

@ -57,6 +57,9 @@ enable = [
# Disabled linters (might want them later) # Disabled linters (might want them later)
# "unparam" # "unparam"
[issues]
exclude-use-default = false
# Enable when appropriate # Enable when appropriate
# Poorly chosen identifier # Poorly chosen identifier
[[issues.exclude-rules]] [[issues.exclude-rules]]
@ -112,3 +115,18 @@ text = "Unknwon` is a misspelling of `Unknown"
[[issues.exclude-rules]] [[issues.exclude-rules]]
linters = ["errorlint"] linters = ["errorlint"]
text = "non-wrapping format verb for fmt.Errorf" text = "non-wrapping format verb for fmt.Errorf"
# TODO: Enable
[[issues.exclude-rules]]
linters = ["stylecheck"]
text = "ST1000"
# TODO: Enable
[[issues.exclude-rules]]
linters = ["stylecheck"]
text = "ST1020"
# TODO: Enable
[[issues.exclude-rules]]
linters = ["stylecheck"]
text = "ST1021"