Commit 3c92f78e by bergquist

feat(cli): add grafana version header to all request against grafana.net

parent 3c966caa
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/commands" "github.com/grafana/grafana/pkg/cmd/grafana-cli/commands"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/utils" "github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
) )
...@@ -16,6 +17,8 @@ var version = "master" ...@@ -16,6 +17,8 @@ var version = "master"
func main() { func main() {
setupLogging() setupLogging()
services.Init(version)
app := cli.NewApp() app := cli.NewApp()
app.Name = "Grafana cli" app.Name = "Grafana cli"
app.Usage = "" app.Usage = ""
......
package services package services
import ( import (
"crypto/tls"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net/http"
"net/url"
"path" "path"
"time"
"github.com/franela/goreq"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models" m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
) )
var IoHelper m.IoUtil = IoUtilImp{} var (
IoHelper m.IoUtil = IoUtilImp{}
HttpClient http.Client
grafanaVersion string
)
func Init(version string) {
grafanaVersion = version
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
}
HttpClient = http.Client{
Timeout: time.Duration(10 * time.Second),
Transport: tr,
}
}
func ListAllPlugins(repoUrl string) (m.PluginRepo, error) { func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
fullUrl := repoUrl + "/repo" body, err := createRequest(repoUrl, "repo")
res, err := goreq.Request{Uri: fullUrl, MaxRedirects: 3}.Do()
if err != nil { if err != nil {
return m.PluginRepo{}, err logger.Info("Failed to create request", "error", err)
return m.PluginRepo{}, fmt.Errorf("Failed to create request. error: %v", err)
} }
if res.StatusCode != 200 {
return m.PluginRepo{}, fmt.Errorf("Could not access %s statuscode %v", fullUrl, res.StatusCode) if err != nil {
return m.PluginRepo{}, err
} }
var resp m.PluginRepo var data m.PluginRepo
err = res.Body.FromJsonTo(&resp) err = json.Unmarshal(body, &data)
if err != nil { if err != nil {
return m.PluginRepo{}, errors.New("Could not load plugin data") logger.Info("Failed to unmarshal graphite response error: %v", err)
return m.PluginRepo{}, err
} }
return resp, nil return data, nil
} }
func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) { func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
...@@ -88,21 +112,48 @@ func RemoveInstalledPlugin(pluginPath, pluginName string) error { ...@@ -88,21 +112,48 @@ func RemoveInstalledPlugin(pluginPath, pluginName string) error {
} }
func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) { func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
fullUrl := repoUrl + "/repo/" + pluginId body, err := createRequest(repoUrl, "repo", pluginId)
if err != nil {
logger.Info("Failed to create request", "error", err)
return m.Plugin{}, fmt.Errorf("Failed to create request. error: %v", err)
}
res, err := goreq.Request{Uri: fullUrl, MaxRedirects: 3}.Do()
if err != nil { if err != nil {
return m.Plugin{}, err return m.Plugin{}, err
} }
if res.StatusCode != 200 {
return m.Plugin{}, fmt.Errorf("Could not access %s statuscode %v", fullUrl, res.StatusCode) var data m.Plugin
err = json.Unmarshal(body, &data)
if err != nil {
logger.Info("Failed to unmarshal graphite response error: %v", err)
return m.Plugin{}, err
}
return data, nil
}
func createRequest(repoUrl string, subPaths ...string) ([]byte, error) {
u, _ := url.Parse(repoUrl)
for _, v := range subPaths {
u.Path = path.Join(u.Path, v)
} }
var resp m.Plugin req, err := http.NewRequest(http.MethodGet, u.String(), nil)
err = res.Body.FromJsonTo(&resp)
logger.Info("grafanaVersion ", grafanaVersion)
req.Header.Set("grafana-version", grafanaVersion)
req.Header.Set("User-Agent", "grafana "+grafanaVersion)
if err != nil { if err != nil {
return m.Plugin{}, errors.New("Could not load plugin data") return []byte{}, err
} }
return resp, nil res, err := HttpClient.Do(req)
body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
return body, err
} }
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
src
language: go
go:
- 1.5.3
- tip
notifications:
email:
- ionathan@gmail.com
- marcosnils@gmail.com
The MIT License (MIT)
Copyright (c) 2013 Jonathan Leibiusky and Marcos Lilljedahl
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
test:
go get -v -d -t ./...
go test -v
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goreq
import (
"strings"
"unicode"
)
// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
}
// Contains reports whether a comma-separated list of options
// contains a particular substr flag. substr must be surrounded by a
// string boundary or commas.
func (o tagOptions) Contains(optionName string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
return true
}
s = next
}
return false
}
func isValidTag(s string) bool {
if s == "" {
return false
}
for _, c := range s {
switch {
case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
// Backslash and quote chars are reserved, but
// otherwise any punctuation chars are allowed
// in a tag name.
default:
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
}
}
return true
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment