Exemple #1
0
func sendUsageStats() {
	log.Trace("Sending anonymous usage stats to stats.grafana.org")

	version := strings.Replace(setting.BuildVersion, ".", "_", -1)

	metrics := map[string]interface{}{}
	report := map[string]interface{}{
		"version": version,
		"metrics": metrics,
	}

	UsageStats.Each(func(name string, i interface{}) {
		switch metric := i.(type) {
		case Counter:
			if metric.Count() > 0 {
				metrics[name+".count"] = metric.Count()
				metric.Clear()
			}
		}
	})

	statsQuery := m.GetSystemStatsQuery{}
	if err := bus.Dispatch(&statsQuery); err != nil {
		log.Error(3, "Failed to get system stats", err)
		return
	}

	metrics["stats.dashboards.count"] = statsQuery.Result.DashboardCount
	metrics["stats.users.count"] = statsQuery.Result.UserCount
	metrics["stats.orgs.count"] = statsQuery.Result.OrgCount
	metrics["stats.playlist.count"] = statsQuery.Result.PlaylistCount
	metrics["stats.plugins.apps.count"] = len(plugins.Apps)
	metrics["stats.plugins.panels.count"] = len(plugins.Panels)
	metrics["stats.plugins.datasources.count"] = len(plugins.DataSources)

	dsStats := m.GetDataSourceStatsQuery{}
	if err := bus.Dispatch(&dsStats); err != nil {
		log.Error(3, "Failed to get datasource stats", err)
		return
	}

	// send counters for each data source
	// but ignore any custom data sources
	// as sending that name could be sensitive information
	dsOtherCount := 0
	for _, dsStat := range dsStats.Result {
		if m.IsKnownDataSourcePlugin(dsStat.Type) {
			metrics["stats.ds."+dsStat.Type+".count"] = dsStat.Count
		} else {
			dsOtherCount += dsStat.Count
		}
	}
	metrics["stats.ds.other.count"] = dsOtherCount

	out, _ := json.MarshalIndent(report, "", " ")
	data := bytes.NewBuffer(out)

	client := http.Client{Timeout: time.Duration(5 * time.Second)}
	go client.Post("https://stats.grafana.org/grafana-usage-report", "application/json", data)
}
Exemple #2
0
func tryLoginUsingRememberCookie(c *middleware.Context) bool {
	// Check auto-login.
	uname := c.GetCookie(setting.CookieUserName)
	if len(uname) == 0 {
		return false
	}

	isSucceed := false
	defer func() {
		if !isSucceed {
			log.Trace("auto-login cookie cleared: %s", uname)
			c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/")
			c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/")
			return
		}
	}()

	userQuery := m.GetUserByLoginQuery{LoginOrEmail: uname}
	if err := bus.Dispatch(&userQuery); err != nil {
		return false
	}

	user := userQuery.Result

	// validate remember me cookie
	if val, _ := c.GetSuperSecureCookie(
		util.EncodeMd5(user.Rands+user.Password), setting.CookieRememberName); val != user.Login {
		return false
	}

	isSucceed = true
	loginUserWithUser(user, c)
	return true
}
Exemple #3
0
func getHeaders(route *plugins.AppPluginRoute, orgId int64, appId string) (http.Header, error) {
	result := http.Header{}

	query := m.GetAppSettingByAppIdQuery{OrgId: orgId, AppId: appId}

	if err := bus.Dispatch(&query); err != nil {
		return nil, err
	}

	data := templateData{
		JsonData:       query.Result.JsonData,
		SecureJsonData: query.Result.SecureJsonData.Decrypt(),
	}

	for _, header := range route.Headers {
		var contentBuf bytes.Buffer
		t, err := template.New("content").Parse(header.Content)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("could not parse header content template for header %s.", header.Name))
		}

		err = t.Execute(&contentBuf, data)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("failed to execute header content template for header %s.", header.Name))
		}

		log.Trace("Adding header to proxy request. %s: %s", header.Name, contentBuf.String())
		result.Add(header.Name, contentBuf.String())
	}

	return result, nil
}
Exemple #4
0
func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	urlPath := r.URL.Path
	hash := urlPath[strings.LastIndex(urlPath, "/")+1:]

	var avatar *Avatar

	if avatar, _ = this.cache[hash]; avatar == nil {
		avatar = New(hash)
	}

	if avatar.Expired() {
		if err := avatar.Update(); err != nil {
			log.Trace("avatar update error: %v", err)
		}
	}

	if avatar.notFound {
		avatar = this.notFound
	} else {
		this.cache[hash] = avatar
	}

	w.Header().Set("Content-Type", "image/jpeg")
	w.Header().Set("Content-Length", strconv.Itoa(len(avatar.data.Bytes())))
	w.Header().Set("Cache-Control", "private, max-age=3600")

	if err := avatar.Encode(w); err != nil {
		log.Warn("avatar encode error: %v", err)
		w.WriteHeader(500)
	}
}
Exemple #5
0
func AuthenticateUnscoped(data *Auth_data) error {
	log.Trace("AuthenticateUnscoped()")
	var auth_post auth_request_struct
	auth_post.Auth.Scope = "unscoped"
	auth_post.Auth.Identity.Methods = []string{"password"}
	auth_post.Auth.Identity.Password.User.Name = data.Username
	auth_post.Auth.Identity.Password.User.Password = data.Password
	auth_post.Auth.Identity.Password.User.Domain.Name = data.Domain
	b, _ := json.Marshal(auth_post)

	return authenticate(data, b)
}
Exemple #6
0
func (a *keystoneAuther) login(query *LoginUserQuery) error {

	log.Trace("perform initial authentication")
	// perform initial authentication
	if err := a.authenticate(query.Username, query.Password); err != nil {
		return err
	}

	log.Trace("Get grafana user")
	if grafanaUser, err := a.getGrafanaUserFor(query.Username); err != nil {
		return err
	} else {
		log.Trace("sync org roles")
		// sync org roles
		if err := a.syncOrgRoles(query.Username, query.Password, grafanaUser); err != nil {
			return err
		}
		query.User = grafanaUser
		return nil
	}

}
Exemple #7
0
func AuthenticateScoped(data *Auth_data) error {
	if data.UnscopedToken != "" {
		log.Trace("AuthenticateScoped() with token")
		var auth_post scoped_auth_token_request_struct
		auth_post.Auth.Identity.Methods = []string{"token"}
		auth_post.Auth.Identity.Token.Id = data.UnscopedToken
		auth_post.Auth.Scope.Project.Domain.Name = data.Domain
		auth_post.Auth.Scope.Project.Name = data.Project
		b, _ := json.Marshal(auth_post)
		return authenticate(data, b)
	} else {
		var auth_post scoped_auth_password_request_struct
		log.Trace("AuthenticateScoped() with password")
		auth_post.Auth.Identity.Methods = []string{"password"}
		auth_post.Auth.Identity.Password.User.Name = data.Username
		auth_post.Auth.Identity.Password.User.Password = data.Password
		auth_post.Auth.Identity.Password.User.Domain.Name = data.Domain
		auth_post.Auth.Scope.Project.Domain.Name = data.Domain
		auth_post.Auth.Scope.Project.Name = data.Project
		b, _ := json.Marshal(auth_post)
		return authenticate(data, b)
	}
}
Exemple #8
0
func processMailQueue() {
	for {
		select {
		case msg := <-mailQueue:
			num, err := buildAndSend(msg)
			tos := strings.Join(msg.To, "; ")
			info := ""
			if err != nil {
				if len(msg.Info) > 0 {
					info = ", info: " + msg.Info
				}
				log.Error(4, fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err))
			} else {
				log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info))
			}
		}
	}
}
Exemple #9
0
func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins.AppPluginRoute, appId string) *httputil.ReverseProxy {
	targetUrl, _ := url.Parse(route.Url)

	director := func(req *http.Request) {

		req.URL.Scheme = targetUrl.Scheme
		req.URL.Host = targetUrl.Host
		req.Host = targetUrl.Host

		req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)

		// clear cookie headers
		req.Header.Del("Cookie")
		req.Header.Del("Set-Cookie")

		//Create a HTTP header with the context in it.
		ctxJson, err := json.Marshal(ctx.SignedInUser)
		if err != nil {
			ctx.JsonApiErr(500, "failed to marshal context to json.", err)
			return
		}

		req.Header.Add("X-Grafana-Context", string(ctxJson))

		if len(route.Headers) > 0 {
			headers, err := getHeaders(route, ctx.OrgId, appId)
			if err != nil {
				ctx.JsonApiErr(500, "Could not generate plugin route header", err)
				return
			}

			for key, value := range headers {
				log.Trace("setting key %v value %v", key, value[0])
				req.Header.Set(key, value[0])
			}
		}

	}

	return &httputil.ReverseProxy{Director: director}
}
Exemple #10
0
func (this *GraphitePublisher) Publish(metrics []Metric) {
	conn, err := net.DialTimeout(this.protocol, this.address, time.Second*5)

	if err != nil {
		log.Error(3, "Metrics: GraphitePublisher:  Failed to connect to %s!", err)
		return
	}

	buf := bytes.NewBufferString("")
	now := time.Now().Unix()

	for _, m := range metrics {
		metricName := this.prefix + m.Name() + m.StringifyTags()

		switch metric := m.(type) {
		case Counter:
			this.addCount(buf, metricName+".count", metric.Count(), now)
		case Gauge:
			this.addCount(buf, metricName, metric.Value(), now)
		case Timer:
			percentiles := metric.Percentiles([]float64{0.25, 0.75, 0.90, 0.99})
			this.addCount(buf, metricName+".count", metric.Count(), now)
			this.addInt(buf, metricName+".max", metric.Max(), now)
			this.addInt(buf, metricName+".min", metric.Min(), now)
			this.addFloat(buf, metricName+".mean", metric.Mean(), now)
			this.addFloat(buf, metricName+".std", metric.StdDev(), now)
			this.addFloat(buf, metricName+".p25", percentiles[0], now)
			this.addFloat(buf, metricName+".p75", percentiles[1], now)
			this.addFloat(buf, metricName+".p90", percentiles[2], now)
			this.addFloat(buf, metricName+".p99", percentiles[3], now)
		}
	}

	log.Trace("Metrics: GraphitePublisher.Publish() \n%s", buf)
	_, err = conn.Write(buf.Bytes())

	if err != nil {
		log.Error(3, "Metrics: GraphitePublisher: Failed to send metrics! %s", err)
	}
}
Exemple #11
0
func sendUsageStats() {
	log.Trace("Sending anonymous usage stats to stats.grafana.org")

	version := strings.Replace(setting.BuildVersion, ".", "_", -1)

	metrics := map[string]interface{}{}
	report := map[string]interface{}{
		"version": version,
		"metrics": metrics,
	}

	statsQuery := m.GetSystemStatsQuery{}
	if err := bus.Dispatch(&statsQuery); err != nil {
		log.Error(3, "Failed to get system stats", err)
		return
	}

	UsageStats.Each(func(name string, i interface{}) {
		switch metric := i.(type) {
		case Counter:
			if metric.Count() > 0 {
				metrics[name+".count"] = metric.Count()
				metric.Clear()
			}
		}
	})

	metrics["stats.dashboards.count"] = statsQuery.Result.DashboardCount
	metrics["stats.users.count"] = statsQuery.Result.UserCount
	metrics["stats.orgs.count"] = statsQuery.Result.OrgCount

	out, _ := json.Marshal(report)
	data := bytes.NewBuffer(out)

	client := http.Client{Timeout: time.Duration(5 * time.Second)}
	go client.Post("https://stats.grafana.org/grafana-usage-report", "application/json", data)
}
Exemple #12
0
func DeleteOrg(cmd *m.DeleteOrgCommand) error {
	return inTransaction2(func(sess *session) error {

		deletes := []string{
			"DELETE FROM star WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ?)",
			"DELETE FROM dashboard_tag WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ?)",
			"DELETE FROM dashboard WHERE org_id = ?",
			"DELETE FROM api_key WHERE org_id = ?",
			"DELETE FROM data_source WHERE org_id = ?",
			"DELETE FROM org_user WHERE org_id = ?",
			"DELETE FROM org WHERE id = ?",
		}

		for _, sql := range deletes {
			log.Trace(sql)
			_, err := sess.Exec(sql, cmd.Id)
			if err != nil {
				return err
			}
		}

		return nil
	})
}
Exemple #13
0
func buildAndSend(msg *Message) (int, error) {
	log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))

	// get message body
	content := msg.Content()

	if len(msg.To) == 0 {
		return 0, fmt.Errorf("empty receive emails")
	} else if len(msg.Body) == 0 {
		return 0, fmt.Errorf("empty email body")
	}

	if msg.Massive {
		// send mail to multiple emails one by one
		num := 0
		for _, to := range msg.To {
			body := []byte("To: " + to + "\r\n" + content)
			err := sendToSmtpServer([]string{to}, body)
			if err != nil {
				return num, err
			}
			num++
		}
		return num, nil
	} else {
		body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)

		// send to multiple emails in one message
		err := sendToSmtpServer(msg.To, body)
		if err != nil {
			return 0, err
		} else {
			return 1, nil
		}
	}
}
Exemple #14
0
func checkForUpdates() {
	log.Trace("Checking for updates")

	client := http.Client{Timeout: time.Duration(5 * time.Second)}

	pluginSlugs := getAllExternalPluginSlugs()
	resp, err := client.Get("https://grafana.net/api/plugins/versioncheck?slugIn=" + pluginSlugs + "&grafanaVersion=" + setting.BuildVersion)

	if err != nil {
		log.Trace("Failed to get plugins repo from grafana.net, %v", err.Error())
		return
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Trace("Update check failed, reading response from grafana.net, %v", err.Error())
		return
	}

	gNetPlugins := []GrafanaNetPlugin{}
	err = json.Unmarshal(body, &gNetPlugins)
	if err != nil {
		log.Trace("Failed to unmarshal plugin repo, reading response from grafana.net, %v", err.Error())
		return
	}

	for _, plug := range Plugins {
		for _, gplug := range gNetPlugins {
			if gplug.Slug == plug.Id {
				plug.GrafanaNetVersion = gplug.Version
				plug.GrafanaNetHasUpdate = plug.Info.Version != plug.GrafanaNetVersion
			}
		}
	}

	resp2, err := client.Get("https://raw.githubusercontent.com/grafana/grafana/master/latest.json")
	if err != nil {
		log.Trace("Failed to get lates.json repo from github: %v", err.Error())
		return
	}

	defer resp2.Body.Close()
	body, err = ioutil.ReadAll(resp2.Body)
	if err != nil {
		log.Trace("Update check failed, reading response from github.net, %v", err.Error())
		return
	}

	var githubLatest GithubLatest
	err = json.Unmarshal(body, &githubLatest)
	if err != nil {
		log.Trace("Failed to unmarshal github latest, reading response from github: %v", err.Error())
		return
	}

	if strings.Contains(setting.BuildVersion, "-") {
		GrafanaLatestVersion = githubLatest.Testing
		GrafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, githubLatest.Testing)
	} else {
		GrafanaLatestVersion = githubLatest.Stable
		GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion
	}
}
Exemple #15
0
func (a *keystoneAuther) syncOrgRoles(username, password string, user *m.User) error {
	log.Trace("syncOrgRoles()")
	err := a.getProjectList(username, password)
	if err != nil {
		return err
	}
	log.Debug("OpenStack project_list[roles]: %v", a.project_list)

	orgsQuery := m.GetUserOrgListQuery{UserId: user.Id}
	if err := bus.Dispatch(&orgsQuery); err != nil {
		return err
	}

	handledOrgIds := map[int64]bool{}

	// update or remove org roles
	for _, org := range orgsQuery.Result {
		handledOrgIds[org.OrgId] = true
		log.Info(fmt.Sprintf("Checking Grafana org %v for roles", org.Name))

		if user_roles, ok := a.project_list[org.Name]; ok {
			// Update roles if user belongs to org
			role_name := a.getRole(user_roles)
			if role_name != "" {
				if err := a.updateGrafanaOrgUser(user.Id, org.OrgId, role_name); err != nil {
					return err
				}
			} else {
				// remove user if no permissions
				if err := a.removeGrafanaOrgUser(user.Id, org.OrgId); err != nil {
					return err
				}
			}
		} else {
			// remove role if no mappings match
			if err := a.removeGrafanaOrgUser(user.Id, org.OrgId); err != nil {
				return err
			}
		}
	}

	// add missing org roles
	for project, _ := range a.project_list {
		if grafanaOrg, err := a.getGrafanaOrgFor(project); err != nil {
			return err
		} else {
			if _, exists := handledOrgIds[grafanaOrg.Id]; exists {
				continue
			}

			// add role
			role_name := a.getRole(a.project_list[project])
			if role_name != "" {
				cmd := m.AddOrgUserCommand{UserId: user.Id, Role: role_name, OrgId: grafanaOrg.Id}
				if err := bus.Dispatch(&cmd); err != nil {
					return err
				}
			}

			// mark this tenant has handled so we do not process it again
			handledOrgIds[grafanaOrg.Id] = true
		}
	}

	// set or unset admin permissions
	isAdmin := false
	role_map := make(map[string]bool)
	for _, role := range a.admin_roles {
		role_map[role] = true
	}
	for project, _ := range a.project_list {
		if isAdmin == true {
			break
		}
		project_roles := a.project_list[project]
		for _, role := range project_roles {
			if _, ok := role_map[role]; ok {
				isAdmin = true
				break
			}
		}
	}
	if isAdmin != user.IsAdmin {
		if err := a.updateGrafanaUserPermissions(user.Id, isAdmin); err != nil {
			return err
		}
	}

	orgsQuery = m.GetUserOrgListQuery{UserId: user.Id}
	if err := bus.Dispatch(&orgsQuery); err != nil {
		return err
	}

	if len(orgsQuery.Result) == 0 {
		return errors.New("Keystone authentication failed: No grafana permissions")
	}

	match := false
	var orgid int64
	for _, org := range orgsQuery.Result {
		orgid = org.OrgId
		if user.OrgId == orgid {
			match = true
			break
		}
	}

	// set org if none is set (for new users), or if user no longer has permissions for the current org
	if (user.OrgId == 1) || (match == false) {
		cmd := m.SetUsingOrgCommand{UserId: user.Id, OrgId: orgid}
		if err := bus.Dispatch(&cmd); err != nil {
			return err
		}
	}

	return nil
}
Exemple #16
0
func OAuthLogin(ctx *middleware.Context) {
	if setting.OAuthService == nil {
		ctx.Handle(404, "login.OAuthLogin(oauth service not enabled)", nil)
		return
	}

	name := ctx.Params(":name")
	connect, ok := social.SocialMap[name]
	if !ok {
		ctx.Handle(404, "login.OAuthLogin(social login not enabled)", errors.New(name))
		return
	}

	code := ctx.Query("code")
	if code == "" {
		ctx.Redirect(connect.AuthCodeURL("", oauth2.AccessTypeOnline))
		return
	}

	// handle call back
	token, err := connect.Exchange(oauth2.NoContext, code)
	if err != nil {
		ctx.Handle(500, "login.OAuthLogin(NewTransportWithCode)", err)
		return
	}

	log.Trace("login.OAuthLogin(Got token)")

	userInfo, err := connect.UserInfo(token)
	if err != nil {
		if err == social.ErrMissingTeamMembership {
			ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github team membership not fulfilled"))
		} else if err == social.ErrMissingOrganizationMembership {
			ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github organization membership not fulfilled"))
		} else {
			ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
		}
		return
	}

	log.Trace("login.OAuthLogin(social login): %s", userInfo)

	// validate that the email is allowed to login to grafana
	if !connect.IsEmailAllowed(userInfo.Email) {
		log.Info("OAuth login attempt with unallowed email, %s", userInfo.Email)
		ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required email domain not fulfilled"))
		return
	}

	userQuery := m.GetUserByLoginQuery{LoginOrEmail: userInfo.Email}
	err = bus.Dispatch(&userQuery)

	// create account if missing
	if err == m.ErrUserNotFound {
		if !connect.IsSignupAllowed() {
			ctx.Redirect(setting.AppSubUrl + "/login")
			return
		}
		limitReached, err := middleware.QuotaReached(ctx, "user")
		if err != nil {
			ctx.Handle(500, "Failed to get user quota", err)
			return
		}
		if limitReached {
			ctx.Redirect(setting.AppSubUrl + "/login")
			return
		}
		cmd := m.CreateUserCommand{
			Login:   userInfo.Email,
			Email:   userInfo.Email,
			Name:    userInfo.Name,
			Company: userInfo.Company,
		}

		if err = bus.Dispatch(&cmd); err != nil {
			ctx.Handle(500, "Failed to create account", err)
			return
		}

		userQuery.Result = &cmd.Result
	} else if err != nil {
		ctx.Handle(500, "Unexpected error", err)
	}

	// login
	loginUserWithUser(userQuery.Result, ctx)

	metrics.M_Api_Login_OAuth.Inc(1)

	ctx.Redirect(setting.AppSubUrl + "/")
}