Add insecure ssl support to connect to kapacitor

pull/2140/head
Chris Goller 2017-10-19 22:48:31 -05:00
parent 7cbdd2b5d2
commit 4b12179b02
6 changed files with 109 additions and 83 deletions

View File

@ -557,13 +557,14 @@ type KapacitorProperty struct {
// Server represents a proxy connection to an HTTP server
type Server struct {
ID int // ID is the unique ID of the server
SrcID int // SrcID of the data source
Name string // Name is the user-defined name for the server
Username string // Username is the username to connect to the server
Password string // Password is in CLEARTEXT
URL string // URL are the connections to the server
Active bool // Is this the active server for the source?
ID int // ID is the unique ID of the server
SrcID int // SrcID of the data source
Name string // Name is the user-defined name for the server
Username string // Username is the username to connect to the server
Password string // Password is in CLEARTEXT
URL string // URL are the connections to the server
InsecureSkipVerify bool // InsecureSkipVerify as true means any certificate presented by the server is accepted.
Active bool // Is this the active server for the source?
}
// ServersStore stores connection information for a `Server`

View File

@ -19,12 +19,13 @@ const (
// Client communicates to kapacitor
type Client struct {
URL string
Username string
Password string
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string) (KapaClient, error)
URL string
Username string
Password string
InsecureSkipVerify bool
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string, insecureSkipVerify bool) (KapaClient, error)
}
// KapaClient represents a connection to a kapacitor instance
@ -37,14 +38,15 @@ type KapaClient interface {
}
// NewClient creates a client that interfaces with Kapacitor tasks
func NewClient(url, username, password string) *Client {
func NewClient(url, username, password string, insecureSkipVerify bool) *Client {
return &Client{
URL: url,
Username: username,
Password: password,
ID: &uuid.V4{},
Ticker: &Alert{},
kapaClient: NewKapaClient,
URL: url,
Username: username,
Password: password,
InsecureSkipVerify: insecureSkipVerify,
ID: &uuid.V4{},
Ticker: &Alert{},
kapaClient: NewKapaClient,
}
}
@ -121,7 +123,7 @@ func (c *Client) Create(ctx context.Context, rule chronograf.AlertRule) (*Task,
return nil, err
}
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return nil, err
}
@ -189,7 +191,7 @@ func (c *Client) createFromQueryConfig(rule chronograf.AlertRule) (*client.Creat
// Delete removes tickscript task from kapacitor
func (c *Client) Delete(ctx context.Context, href string) error {
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return err
}
@ -197,7 +199,7 @@ func (c *Client) Delete(ctx context.Context, href string) error {
}
func (c *Client) updateStatus(ctx context.Context, href string, status client.TaskStatus) (*Task, error) {
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return nil, err
}
@ -235,7 +237,7 @@ func (c *Client) Status(ctx context.Context, href string) (string, error) {
}
func (c *Client) status(ctx context.Context, href string) (client.TaskStatus, error) {
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return 0, err
}
@ -249,7 +251,7 @@ func (c *Client) status(ctx context.Context, href string) (client.TaskStatus, er
// All returns all tasks in kapacitor
func (c *Client) All(ctx context.Context) (map[string]*Task, error) {
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return nil, err
}
@ -286,7 +288,7 @@ func (c *Client) Reverse(id string, script chronograf.TICKScript) chronograf.Ale
// Get returns a single alert in kapacitor
func (c *Client) Get(ctx context.Context, id string) (*Task, error) {
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return nil, err
}
@ -301,7 +303,7 @@ func (c *Client) Get(ctx context.Context, id string) (*Task, error) {
// Update changes the tickscript of a given id.
func (c *Client) Update(ctx context.Context, href string, rule chronograf.AlertRule) (*Task, error) {
kapa, err := c.kapaClient(c.URL, c.Username, c.Password)
kapa, err := c.kapaClient(c.URL, c.Username, c.Password, c.InsecureSkipVerify)
if err != nil {
return nil, err
}
@ -386,7 +388,7 @@ func toTask(q *chronograf.QueryConfig) client.TaskType {
}
// NewKapaClient creates a Kapacitor client connection
func NewKapaClient(url, username, password string) (KapaClient, error) {
func NewKapaClient(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
var creds *client.Credentials
if username != "" {
creds = &client.Credentials{
@ -397,8 +399,9 @@ func NewKapaClient(url, username, password string) (KapaClient, error) {
}
clnt, err := client.New(client.Config{
URL: url,
Credentials: creds,
URL: url,
Credentials: creds,
InsecureSkipVerify: insecureSkipVerify,
})
if err != nil {

View File

@ -75,7 +75,7 @@ func TestClient_All(t *testing.T) {
Password string
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string) (KapaClient, error)
kapaClient func(url, username, password string, insecureSkipVerify bool) (KapaClient, error)
}
type args struct {
ctx context.Context
@ -100,7 +100,7 @@ func TestClient_All(t *testing.T) {
{
name: "return no tasks",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
},
@ -110,7 +110,7 @@ func TestClient_All(t *testing.T) {
{
name: "return a non-reversible task",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
},
@ -141,7 +141,7 @@ func TestClient_All(t *testing.T) {
{
name: "return a reversible task",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
},
@ -380,7 +380,7 @@ func TestClient_Get(t *testing.T) {
Password string
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string) (KapaClient, error)
kapaClient func(url, username, password string, insecureSkipVerify bool) (KapaClient, error)
}
type args struct {
ctx context.Context
@ -406,7 +406,7 @@ func TestClient_Get(t *testing.T) {
{
name: "return no task",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
},
@ -423,7 +423,7 @@ func TestClient_Get(t *testing.T) {
{
name: "return non-reversible task",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
},
@ -465,7 +465,7 @@ func TestClient_Get(t *testing.T) {
{
name: "return reversible task",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
},
@ -706,7 +706,7 @@ func TestClient_updateStatus(t *testing.T) {
Password string
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string) (KapaClient, error)
kapaClient func(url, username, password string, insecureSkipVerify bool) (KapaClient, error)
}
type args struct {
ctx context.Context
@ -727,7 +727,7 @@ func TestClient_updateStatus(t *testing.T) {
{
name: "disable alert rule",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -777,7 +777,7 @@ func TestClient_updateStatus(t *testing.T) {
{
name: "fail to enable alert rule",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -797,7 +797,7 @@ func TestClient_updateStatus(t *testing.T) {
{
name: "enable alert rule",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -880,7 +880,7 @@ func TestClient_Update(t *testing.T) {
Password string
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string) (KapaClient, error)
kapaClient func(url, username, password string, insecureSkipVerify bool) (KapaClient, error)
}
type args struct {
ctx context.Context
@ -902,7 +902,7 @@ func TestClient_Update(t *testing.T) {
{
name: "update alert rule error",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -936,7 +936,7 @@ func TestClient_Update(t *testing.T) {
{
name: "update alert rule",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -1000,7 +1000,7 @@ func TestClient_Update(t *testing.T) {
{
name: "stays disabled when already disabled",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -1099,7 +1099,7 @@ func TestClient_Create(t *testing.T) {
Password string
ID chronograf.ID
Ticker chronograf.Ticker
kapaClient func(url, username, password string) (KapaClient, error)
kapaClient func(url, username, password string, insecureSkipVerify bool) (KapaClient, error)
}
type args struct {
ctx context.Context
@ -1119,7 +1119,7 @@ func TestClient_Create(t *testing.T) {
{
name: "create alert rule",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},
@ -1185,7 +1185,7 @@ func TestClient_Create(t *testing.T) {
{
name: "create alert rule error",
fields: fields{
kapaClient: func(url, username, password string) (KapaClient, error) {
kapaClient: func(url, username, password string, insecureSkipVerify bool) (KapaClient, error) {
return kapa, nil
},
Ticker: &Alert{},

View File

@ -12,11 +12,12 @@ import (
)
type postKapacitorRequest struct {
Name *string `json:"name"` // User facing name of kapacitor instance.; Required: true
URL *string `json:"url"` // URL for the kapacitor backend (e.g. http://localhost:9092);/ Required: true
Username string `json:"username,omitempty"` // Username for authentication to kapacitor
Password string `json:"password,omitempty"`
Active bool `json:"active"`
Name *string `json:"name"` // User facing name of kapacitor instance.; Required: true
URL *string `json:"url"` // URL for the kapacitor backend (e.g. http://localhost:9092);/ Required: true
Username string `json:"username,omitempty"` // Username for authentication to kapacitor
Password string `json:"password,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted.
Active bool `json:"active"`
}
func (p *postKapacitorRequest) Valid() error {
@ -44,13 +45,14 @@ type kapaLinks struct {
}
type kapacitor struct {
ID int `json:"id,string"` // Unique identifier representing a kapacitor instance.
Name string `json:"name"` // User facing name of kapacitor instance.
URL string `json:"url"` // URL for the kapacitor backend (e.g. http://localhost:9092)
Username string `json:"username,omitempty"` // Username for authentication to kapacitor
Password string `json:"password,omitempty"`
Active bool `json:"active"`
Links kapaLinks `json:"links"` // Links are URI locations related to kapacitor
ID int `json:"id,string"` // Unique identifier representing a kapacitor instance.
Name string `json:"name"` // User facing name of kapacitor instance.
URL string `json:"url"` // URL for the kapacitor backend (e.g. http://localhost:9092)
Username string `json:"username,omitempty"` // Username for authentication to kapacitor
Password string `json:"password,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted.
Active bool `json:"active"`
Links kapaLinks `json:"links"` // Links are URI locations related to kapacitor
}
// NewKapacitor adds valid kapacitor store store.
@ -79,12 +81,13 @@ func (h *Service) NewKapacitor(w http.ResponseWriter, r *http.Request) {
}
srv := chronograf.Server{
SrcID: srcID,
Name: *req.Name,
Username: req.Username,
Password: req.Password,
URL: *req.URL,
Active: req.Active,
SrcID: srcID,
Name: *req.Name,
Username: req.Username,
Password: req.Password,
InsecureSkipVerify: req.InsecureSkipVerify,
URL: *req.URL,
Active: req.Active,
}
if srv, err = h.ServersStore.Add(ctx, srv); err != nil {
@ -101,11 +104,12 @@ func (h *Service) NewKapacitor(w http.ResponseWriter, r *http.Request) {
func newKapacitor(srv chronograf.Server) kapacitor {
httpAPISrcs := "/chronograf/v1/sources"
return kapacitor{
ID: srv.ID,
Name: srv.Name,
Username: srv.Username,
URL: srv.URL,
Active: srv.Active,
ID: srv.ID,
Name: srv.Name,
Username: srv.Username,
URL: srv.URL,
Active: srv.Active,
InsecureSkipVerify: srv.InsecureSkipVerify,
Links: kapaLinks{
Self: fmt.Sprintf("%s/%d/kapacitors/%d", httpAPISrcs, srv.SrcID, srv.ID),
Proxy: fmt.Sprintf("%s/%d/kapacitors/%d/proxy", httpAPISrcs, srv.SrcID, srv.ID),
@ -204,11 +208,12 @@ func (h *Service) RemoveKapacitor(w http.ResponseWriter, r *http.Request) {
}
type patchKapacitorRequest struct {
Name *string `json:"name,omitempty"` // User facing name of kapacitor instance.
URL *string `json:"url,omitempty"` // URL for the kapacitor
Username *string `json:"username,omitempty"` // Username for kapacitor auth
Password *string `json:"password,omitempty"`
Active *bool `json:"active"`
Name *string `json:"name,omitempty"` // User facing name of kapacitor instance.
URL *string `json:"url,omitempty"` // URL for the kapacitor
Username *string `json:"username,omitempty"` // Username for kapacitor auth
Password *string `json:"password,omitempty"`
InsecureSkipVerify *bool `json:"insecureSkipVerify,omitempty"` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted.
Active *bool `json:"active"`
}
func (p *patchKapacitorRequest) Valid() error {
@ -268,6 +273,9 @@ func (h *Service) UpdateKapacitor(w http.ResponseWriter, r *http.Request) {
if req.Username != nil {
srv.Username = *req.Username
}
if req.InsecureSkipVerify != nil {
srv.InsecureSkipVerify = *req.InsecureSkipVerify
}
if req.Active != nil {
srv.Active = *req.Active
}
@ -303,7 +311,7 @@ func (h *Service) KapacitorRulesPost(w http.ResponseWriter, r *http.Request) {
return
}
c := kapa.NewClient(srv.URL, srv.Username, srv.Password)
c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify)
var req chronograf.AlertRule
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
@ -440,7 +448,7 @@ func (h *Service) KapacitorRulesPut(w http.ResponseWriter, r *http.Request) {
}
tid := httprouter.GetParamFromContext(ctx, "tid")
c := kapa.NewClient(srv.URL, srv.Username, srv.Password)
c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify)
var req chronograf.AlertRule
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
invalidJSON(w, h.Logger)
@ -510,7 +518,7 @@ func (h *Service) KapacitorRulesStatus(w http.ResponseWriter, r *http.Request) {
}
tid := httprouter.GetParamFromContext(ctx, "tid")
c := kapa.NewClient(srv.URL, srv.Username, srv.Password)
c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify)
var req KapacitorStatus
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
@ -570,7 +578,7 @@ func (h *Service) KapacitorRulesGet(w http.ResponseWriter, r *http.Request) {
return
}
c := kapa.NewClient(srv.URL, srv.Username, srv.Password)
c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify)
tasks, err := c.All(ctx)
if err != nil {
Error(w, http.StatusInternalServerError, err.Error(), h.Logger)
@ -613,7 +621,7 @@ func (h *Service) KapacitorRulesID(w http.ResponseWriter, r *http.Request) {
}
tid := httprouter.GetParamFromContext(ctx, "tid")
c := kapa.NewClient(srv.URL, srv.Username, srv.Password)
c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify)
// Check if the rule exists within scope
task, err := c.Get(ctx, tid)
@ -651,7 +659,7 @@ func (h *Service) KapacitorRulesDelete(w http.ResponseWriter, r *http.Request) {
return
}
c := kapa.NewClient(srv.URL, srv.Username, srv.Password)
c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify)
tid := httprouter.GetParamFromContext(ctx, "tid")
// Check if the rule is linked to this server and kapacitor

View File

@ -174,6 +174,14 @@ func Test_KapacitorRulesGet(t *testing.T) {
// setup mock service and test logger
testLogger := mocks.TestLogger{}
svc := &server.Service{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
return chronograf.Source{
ID: ID,
InsecureSkipVerify: true,
}, nil
},
},
ServersStore: &mocks.ServersStore{
GetF: func(ctx context.Context, ID int) (chronograf.Server, error) {
return chronograf.Server{

View File

@ -2357,6 +2357,7 @@
"name": "kapa",
"url": "http://localhost:9092",
"active": false,
"insecureSkipVerify": false,
"links": {
"proxy": "/chronograf/v1/sources/4/kapacitors/4/proxy",
"self": "/chronograf/v1/sources/4/kapacitors/4",
@ -2387,6 +2388,11 @@
"description":
"URL for the kapacitor backend (e.g. http://localhost:9092)"
},
"insecureSkipVerify": {
"type": "boolean",
"description":
"True means any certificate presented by the kapacitor is accepted. Typically used for self-signed certs. Probably should only be used for testing."
},
"active": {
"type": "boolean",
"description":