Merge pull request #154 from influxdata/feature/mock-sources

Add interface and mock for sources
pull/10616/head
Chris Goller 2016-09-30 10:40:00 -05:00 committed by GitHub
commit 2c65b53ccf
13 changed files with 392 additions and 85 deletions

View File

@ -1,6 +1,9 @@
package handlers
import (
"fmt"
"strconv"
"github.com/go-openapi/runtime/middleware"
"github.com/influxdata/mrfusion"
"github.com/influxdata/mrfusion/models"
@ -10,11 +13,28 @@ import (
)
type InfluxProxy struct {
Srcs mrfusion.SourcesStore
TimeSeries mrfusion.TimeSeries
}
func (h *InfluxProxy) Proxy(ctx context.Context, params op.PostSourcesIDProxyParams) middleware.Responder {
// TODO: Add support for multiple TimeSeries with lookup based on params.ID
id, err := strconv.Atoi(params.ID)
if err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error converting ID %s", params.ID)}
return op.NewPostSourcesIDProxyDefault(500).WithPayload(errMsg)
}
src, err := h.Srcs.Get(ctx, id)
if err != nil {
errMsg := &models.Error{Code: 404, Message: fmt.Sprintf("Unknown ID %s", params.ID)}
return op.NewPostSourcesIDProxyNotFound().WithPayload(errMsg)
}
if err = h.TimeSeries.Connect(ctx, &src); err != nil {
errMsg := &models.Error{Code: 400, Message: fmt.Sprintf("Unable to connect to source %s", params.ID)}
return op.NewPostSourcesIDProxyNotFound().WithPayload(errMsg)
}
query := mrfusion.Query{
Command: *params.Query.Query,
DB: params.Query.Db,

View File

@ -59,6 +59,9 @@ func query(u *url.URL, q mrfusion.Query) (mrfusion.Response, error) {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("received status code %d from server", resp.StatusCode)
}
var response Response
dec := json.NewDecoder(resp.Body)
@ -73,6 +76,7 @@ func query(u *url.URL, q mrfusion.Query) (mrfusion.Response, error) {
if decErr != nil {
return nil, fmt.Errorf("unable to decode json: received status code %d err: %s", resp.StatusCode, decErr)
}
// If we don't have an error in our json response, and didn't get statusOK
// then send back an error
if resp.StatusCode != http.StatusOK && response.Err != "" {
@ -111,3 +115,13 @@ func (c *Client) Query(ctx context.Context, q mrfusion.Query) (mrfusion.Response
func (c *Client) MonitoredServices(ctx context.Context) ([]mrfusion.MonitoredService, error) {
return []mrfusion.MonitoredService{}, nil
}
func (c *Client) Connect(ctx context.Context, src *mrfusion.Source) error {
u, err := url.Parse(src.URL[0])
if err != nil {
return err
}
u.User = url.UserPassword(src.Username, src.Password)
c.URL = u
return nil
}

View File

@ -16,70 +16,154 @@ import (
type Handler struct {
Store mrfusion.ExplorationStore
Srcs mrfusion.SourcesStore
TimeSeries mrfusion.TimeSeries
}
func NewHandler() Handler {
return Handler{
DefaultExplorationStore,
DefaultTimeSeries,
h := Handler{
Store: DefaultExplorationStore,
Srcs: DefaultSourcesStore,
TimeSeries: DefaultTimeSeries,
}
return h
}
func sampleSource() *models.Source {
name := "muh name"
url := "http://localhost:8086"
return &models.Source{
ID: "1",
Links: &models.SourceLinks{
Self: "/chronograf/v1/sources/1",
Proxy: "/chronograf/v1/sources/1/proxy",
},
Name: &name,
Type: "influx-enterprise",
Username: "HOWDY!",
Password: "changeme",
URL: &url,
func (m *Handler) AllRoutes(ctx context.Context, params op.GetParams) middleware.Responder {
routes := &models.Routes{
Sources: "/chronograf/v1/sources",
Dashboards: "/chronograf/v1/dashboards",
Apps: "/chronograf/v1/apps",
Users: "/chronograf/v1/users",
}
return op.NewGetOK().WithPayload(routes)
}
func (m *Handler) NewSource(ctx context.Context, params op.PostSourcesParams) middleware.Responder {
return op.NewPostSourcesCreated()
src := mrfusion.Source{
Name: *params.Source.Name,
Type: params.Source.Type,
Username: params.Source.Username,
Password: params.Source.Password,
URL: []string{*params.Source.URL},
Default: params.Source.Default,
}
var err error
if src, err = m.Srcs.Add(ctx, src); err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error storing source %v: %v", params.Source, err)}
return op.NewPostSourcesDefault(500).WithPayload(errMsg)
}
mSrc := mrToModel(src)
return op.NewPostSourcesCreated().WithPayload(mSrc).WithLocation(mSrc.Links.Self)
}
func srcLinks(id int) *models.SourceLinks {
return &models.SourceLinks{
Self: fmt.Sprintf("/chronograf/v1/sources/%d", id),
Proxy: fmt.Sprintf("/chronograf/v1/sources/%d/proxy", id),
Users: fmt.Sprintf("/chronograf/v1/sources/%d/users", id),
Roles: fmt.Sprintf("/chronograf/v1/sources/%d/roles", id),
Permissions: fmt.Sprintf("/chronograf/v1/sources/%d/permissions", id),
}
}
func mrToModel(src mrfusion.Source) *models.Source {
return &models.Source{
ID: strconv.Itoa(src.ID),
Links: srcLinks(src.ID),
Name: &src.Name,
Type: src.Type,
Username: src.Username,
Password: src.Password,
URL: &src.URL[0],
Default: src.Default,
}
}
func (m *Handler) Sources(ctx context.Context, params op.GetSourcesParams) middleware.Responder {
mrSrcs, err := m.Srcs.All(ctx)
if err != nil {
errMsg := &models.Error{Code: 500, Message: "Error loading sources"}
return op.NewGetSourcesDefault(500).WithPayload(errMsg)
}
srcs := make([]*models.Source, len(mrSrcs))
for i, src := range mrSrcs {
srcs[i] = mrToModel(src)
}
res := &models.Sources{
Sources: []*models.Source{
sampleSource(),
},
Sources: srcs,
}
return op.NewGetSourcesOK().WithPayload(res)
}
func (m *Handler) SourcesID(ctx context.Context, params op.GetSourcesIDParams) middleware.Responder {
if params.ID != "1" {
return op.NewGetSourcesIDNotFound()
id, err := strconv.Atoi(params.ID)
if err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error converting ID %s", params.ID)}
return op.NewGetSourcesIDDefault(500).WithPayload(errMsg)
}
return op.NewGetSourcesIDOK().WithPayload(sampleSource())
src, err := m.Srcs.Get(ctx, id)
if err != nil {
errMsg := &models.Error{Code: 404, Message: fmt.Sprintf("Unknown ID %s", params.ID)}
return op.NewGetSourcesIDNotFound().WithPayload(errMsg)
}
return op.NewGetSourcesIDOK().WithPayload(mrToModel(src))
}
func (m *Handler) Proxy(ctx context.Context, params op.PostSourcesIDProxyParams) middleware.Responder {
query := mrfusion.Query{
Command: *params.Query.Query,
DB: params.Query.Db,
RP: params.Query.Rp,
}
response, err := m.TimeSeries.Query(ctx, mrfusion.Query(query))
func (m *Handler) RemoveSource(ctx context.Context, params op.DeleteSourcesIDParams) middleware.Responder {
id, err := strconv.Atoi(params.ID)
if err != nil {
return op.NewPostSourcesIDProxyDefault(500)
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error converting ID %s", params.ID)}
return op.NewDeleteSourcesIDDefault(500).WithPayload(errMsg)
}
src := mrfusion.Source{
ID: id,
}
if err = m.Srcs.Delete(ctx, src); err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Unknown error deleting source %s", params.ID)}
return op.NewDeleteSourcesIDDefault(500).WithPayload(errMsg)
}
res := &models.ProxyResponse{
Results: response,
return op.NewDeleteSourcesIDNoContent()
}
func (m *Handler) UpdateSource(ctx context.Context, params op.PatchSourcesIDParams) middleware.Responder {
id, err := strconv.Atoi(params.ID)
if err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error converting ID %s", params.ID)}
return op.NewPatchSourcesIDDefault(500).WithPayload(errMsg)
}
return op.NewPostSourcesIDProxyOK().WithPayload(res)
src, err := m.Srcs.Get(ctx, id)
if err != nil {
errMsg := &models.Error{Code: 404, Message: fmt.Sprintf("Unknown ID %s", params.ID)}
return op.NewPatchSourcesIDNotFound().WithPayload(errMsg)
}
src.Default = params.Config.Default
if params.Config.Name != nil {
src.Name = *params.Config.Name
}
if params.Config.Password != "" {
src.Password = params.Config.Password
}
if params.Config.Username != "" {
src.Username = params.Config.Username
}
if params.Config.URL != nil {
src.URL = []string{*params.Config.URL}
}
if params.Config.Type != "" {
src.Type = params.Config.Type
}
if err := m.Srcs.Update(ctx, src); err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error updating source ID %s", params.ID)}
return op.NewPatchSourcesIDDefault(500).WithPayload(errMsg)
}
return op.NewPatchSourcesIDNoContent()
}
func (m *Handler) MonitoredServices(ctx context.Context, params op.GetSourcesIDMonitoredParams) middleware.Responder {
@ -98,6 +182,39 @@ func (m *Handler) MonitoredServices(ctx context.Context, params op.GetSourcesIDM
return op.NewGetSourcesIDMonitoredOK().WithPayload(res)
}
func (m *Handler) Proxy(ctx context.Context, params op.PostSourcesIDProxyParams) middleware.Responder {
id, err := strconv.Atoi(params.ID)
if err != nil {
errMsg := &models.Error{Code: 500, Message: fmt.Sprintf("Error converting ID %s", params.ID)}
return op.NewPostSourcesIDProxyDefault(500).WithPayload(errMsg)
}
src, err := m.Srcs.Get(ctx, id)
if err != nil {
errMsg := &models.Error{Code: 404, Message: fmt.Sprintf("Unknown ID %s", params.ID)}
return op.NewPostSourcesIDProxyNotFound().WithPayload(errMsg)
}
if err = m.TimeSeries.Connect(ctx, &src); err != nil {
errMsg := &models.Error{Code: 400, Message: fmt.Sprintf("Unable to connect to source %s", params.ID)}
return op.NewPostSourcesIDProxyNotFound().WithPayload(errMsg)
}
query := mrfusion.Query{
Command: *params.Query.Query,
DB: params.Query.Db,
RP: params.Query.Rp,
}
response, err := m.TimeSeries.Query(ctx, mrfusion.Query(query))
if err != nil {
return op.NewPostSourcesIDProxyDefault(500)
}
res := &models.ProxyResponse{
Results: response,
}
return op.NewPostSourcesIDProxyOK().WithPayload(res)
}
func (m *Handler) Explorations(ctx context.Context, params op.GetSourcesIDUsersUserIDExplorationsParams) middleware.Responder {
id, err := strconv.Atoi(params.UserID)
if err != nil {

View File

@ -8,6 +8,62 @@ import (
"golang.org/x/net/context"
)
type SourcesStore struct {
srcs map[int]mrfusion.Source
}
func NewSourcesStore() mrfusion.SourcesStore {
return &SourcesStore{
srcs: map[int]mrfusion.Source{},
}
}
func (s *SourcesStore) All(ctx context.Context) ([]mrfusion.Source, error) {
all := []mrfusion.Source{}
for _, src := range s.srcs {
all = append(all, src)
}
return all, nil
}
func (s *SourcesStore) Add(ctx context.Context, src mrfusion.Source) (mrfusion.Source, error) {
id := len(s.srcs) + 1
for k, _ := range s.srcs {
if k >= id {
id = k + 1
break
}
}
src.ID = id
s.srcs[id] = src
return src, nil
}
func (s *SourcesStore) Delete(ctx context.Context, src mrfusion.Source) error {
if _, ok := s.srcs[src.ID]; !ok {
return fmt.Errorf("Error unknown id %d", src.ID)
}
delete(s.srcs, src.ID)
return nil
}
func (s *SourcesStore) Get(ctx context.Context, ID int) (mrfusion.Source, error) {
if src, ok := s.srcs[ID]; ok {
return src, nil
}
return mrfusion.Source{}, fmt.Errorf("Error no such source %d", ID)
}
func (s *SourcesStore) Update(ctx context.Context, src mrfusion.Source) error {
if _, ok := s.srcs[src.ID]; !ok {
return fmt.Errorf("Error unknown ID %d", src.ID)
}
s.srcs[src.ID] = src
return nil
}
var DefaultSourcesStore mrfusion.SourcesStore = NewSourcesStore()
type ExplorationStore struct {
db map[int]*mrfusion.Exploration
NowFunc func() time.Time
@ -99,6 +155,10 @@ func (t *TimeSeries) Query(context.Context, mrfusion.Query) (mrfusion.Response,
return t.Response, nil
}
func (t *TimeSeries) Connect(ctx context.Context, src *mrfusion.Source) error {
return nil
}
func (t *TimeSeries) MonitoredServices(context.Context) ([]mrfusion.MonitoredService, error) {
hosts := make([]mrfusion.MonitoredService, len(t.Hosts))
for i, name := range t.Hosts {

43
models/routes.go Normal file
View File

@ -0,0 +1,43 @@
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
)
/*Routes routes
swagger:model Routes
*/
type Routes struct {
/* Location of the apps endpoint
*/
Apps string `json:"apps,omitempty"`
/* Location of the dashboards endpoint
*/
Dashboards string `json:"dashboards,omitempty"`
/* Location of the sources endpoint
*/
Sources string `json:"sources,omitempty"`
/* Location of the users endpoint
*/
Users string `json:"users,omitempty"`
}
// Validate validates this routes
func (m *Routes) Validate(formats strfmt.Registry) error {
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@ -8,6 +8,7 @@ import (
"github.com/go-openapi/swag"
"github.com/go-openapi/errors"
"github.com/go-openapi/validate"
)
/*Sources sources
@ -17,8 +18,10 @@ swagger:model Sources
type Sources struct {
/* sources
*/
Sources []*Source `json:"sources,omitempty"`
Required: true
*/
Sources []*Source `json:"sources"`
}
// Validate validates this sources
@ -38,8 +41,8 @@ func (m *Sources) Validate(formats strfmt.Registry) error {
func (m *Sources) validateSources(formats strfmt.Registry) error {
if swag.IsZero(m.Sources) { // not required
return nil
if err := validate.Required("sources", "body", m.Sources); err != nil {
return err
}
for i := 0; i < len(m.Sources); i++ {

View File

@ -86,6 +86,8 @@ func configureAPI(api *operations.MrFusionAPI) http.Handler {
mockHandler := mock.NewHandler()
api.GetHandler = operations.GetHandlerFunc(mockHandler.AllRoutes)
if len(storeFlags.BoltPath) > 0 {
c := bolt.NewClient()
c.Path = storeFlags.BoltPath
@ -108,12 +110,28 @@ func configureAPI(api *operations.MrFusionAPI) http.Handler {
api.PostSourcesIDUsersUserIDExplorationsHandler = operations.PostSourcesIDUsersUserIDExplorationsHandlerFunc(mockHandler.NewExploration)
}
api.DeleteDashboardsIDHandler = operations.DeleteDashboardsIDHandlerFunc(func(ctx context.Context, params operations.DeleteDashboardsIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteDashboardsID has not yet been implemented")
})
api.DeleteSourcesIDHandler = operations.DeleteSourcesIDHandlerFunc(func(ctx context.Context, params operations.DeleteSourcesIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteSourcesID has not yet been implemented")
})
api.DeleteSourcesIDHandler = operations.DeleteSourcesIDHandlerFunc(mockHandler.RemoveSource)
api.PatchSourcesIDHandler = operations.PatchSourcesIDHandlerFunc(mockHandler.UpdateSource)
api.GetSourcesHandler = operations.GetSourcesHandlerFunc(mockHandler.Sources)
api.GetSourcesIDHandler = operations.GetSourcesIDHandlerFunc(mockHandler.SourcesID)
api.PostSourcesHandler = operations.PostSourcesHandlerFunc(mockHandler.NewSource)
if len(influxFlags.Server) > 0 {
c, err := influx.NewClient(influxFlags.Server)
if err != nil {
panic(err)
}
// TODO: Change to bolt when finished
h := handlers.InfluxProxy{
Srcs: mock.DefaultSourcesStore,
TimeSeries: c,
}
api.PostSourcesIDProxyHandler = operations.PostSourcesIDProxyHandlerFunc(h.Proxy)
} else {
api.PostSourcesIDProxyHandler = operations.PostSourcesIDProxyHandlerFunc(mockHandler.Proxy)
}
api.DeleteSourcesIDRolesRoleIDHandler = operations.DeleteSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params operations.DeleteSourcesIDRolesRoleIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteSourcesIDRolesRoleID has not yet been implemented")
})
@ -121,8 +139,9 @@ func configureAPI(api *operations.MrFusionAPI) http.Handler {
api.DeleteSourcesIDUsersUserIDHandler = operations.DeleteSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params operations.DeleteSourcesIDUsersUserIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteSourcesIDUsersUserID has not yet been implemented")
})
api.GetHandler = operations.GetHandlerFunc(func(ctx context.Context, params operations.GetParams) middleware.Responder {
return middleware.NotImplemented("operation .Get has not yet been implemented")
api.DeleteDashboardsIDHandler = operations.DeleteDashboardsIDHandlerFunc(func(ctx context.Context, params operations.DeleteDashboardsIDParams) middleware.Responder {
return middleware.NotImplemented("operation .DeleteDashboardsID has not yet been implemented")
})
api.GetDashboardsHandler = operations.GetDashboardsHandlerFunc(func(ctx context.Context, params operations.GetDashboardsParams) middleware.Responder {
return middleware.NotImplemented("operation .GetDashboards has not yet been implemented")
@ -131,9 +150,6 @@ func configureAPI(api *operations.MrFusionAPI) http.Handler {
return middleware.NotImplemented("operation .GetDashboardsID has not yet been implemented")
})
api.GetSourcesHandler = operations.GetSourcesHandlerFunc(mockHandler.Sources)
api.GetSourcesIDHandler = operations.GetSourcesIDHandlerFunc(mockHandler.SourcesID)
api.GetSourcesIDPermissionsHandler = operations.GetSourcesIDPermissionsHandlerFunc(func(ctx context.Context, params operations.GetSourcesIDPermissionsParams) middleware.Responder {
return middleware.NotImplemented("operation .GetSourcesIDPermissions has not yet been implemented")
})
@ -151,9 +167,6 @@ func configureAPI(api *operations.MrFusionAPI) http.Handler {
return middleware.NotImplemented("operation .GetSourcesIDUsersUserID has not yet been implemented")
})
api.PatchSourcesIDHandler = operations.PatchSourcesIDHandlerFunc(func(ctx context.Context, params operations.PatchSourcesIDParams) middleware.Responder {
return middleware.NotImplemented("operation .PatchSourcesID has not yet been implemented")
})
api.PatchSourcesIDRolesRoleIDHandler = operations.PatchSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params operations.PatchSourcesIDRolesRoleIDParams) middleware.Responder {
return middleware.NotImplemented("operation .PatchSourcesIDRolesRoleID has not yet been implemented")
})
@ -164,20 +177,6 @@ func configureAPI(api *operations.MrFusionAPI) http.Handler {
api.PostDashboardsHandler = operations.PostDashboardsHandlerFunc(func(ctx context.Context, params operations.PostDashboardsParams) middleware.Responder {
return middleware.NotImplemented("operation .PostDashboards has not yet been implemented")
})
api.PostSourcesHandler = operations.PostSourcesHandlerFunc(mockHandler.NewSource)
if len(influxFlags.Server) > 0 {
c, err := influx.NewClient(influxFlags.Server)
if err != nil {
panic(err)
}
h := handlers.InfluxProxy{
TimeSeries: c,
}
api.PostSourcesIDProxyHandler = operations.PostSourcesIDProxyHandlerFunc(h.Proxy)
} else {
api.PostSourcesIDProxyHandler = operations.PostSourcesIDProxyHandlerFunc(mockHandler.Proxy)
}
api.PostSourcesIDRolesHandler = operations.PostSourcesIDRolesHandlerFunc(func(ctx context.Context, params operations.PostSourcesIDRolesParams) middleware.Responder {
return middleware.NotImplemented("operation .PostSourcesIDRoles has not yet been implemented")

View File

@ -18,7 +18,7 @@ swagger:response getOK
type GetOK struct {
// In: body
Payload *models.Links `json:"body,omitempty"`
Payload *models.Routes `json:"body,omitempty"`
}
// NewGetOK creates GetOK with default headers values
@ -27,13 +27,13 @@ func NewGetOK() *GetOK {
}
// WithPayload adds the payload to the get o k response
func (o *GetOK) WithPayload(payload *models.Links) *GetOK {
func (o *GetOK) WithPayload(payload *models.Routes) *GetOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get o k response
func (o *GetOK) SetPayload(payload *models.Links) {
func (o *GetOK) SetPayload(payload *models.Routes) {
o.Payload = payload
}

View File

@ -2,11 +2,11 @@ package restapi
import (
"crypto/tls"
"fmt"
"log"
"net"
"net/http"
"os"
"strconv"
"sync"
"time"
@ -213,6 +213,11 @@ func (s *Server) Listen() error {
if s.TLSCertificateKey == "" {
s.Fatalf("the required flag `--tls-key` was not specified")
}
// Use http host if https host wasn't defined
if s.TLSHost == "" {
s.TLSHost = s.Host
}
}
if s.hasScheme(schemeUnix) {
@ -224,7 +229,7 @@ func (s *Server) Listen() error {
}
if s.hasScheme(schemeHTTP) {
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Host, s.Port))
listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
if err != nil {
return err
}
@ -239,10 +244,7 @@ func (s *Server) Listen() error {
}
if s.hasScheme(schemeHTTPS) {
if s.TLSHost == "" {
s.TLSHost = s.Host
}
tlsListener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.TLSHost, s.TLSPort))
tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
if err != nil {
return err
}

View File

@ -105,12 +105,38 @@ type Dashboard struct {
// DashboardStore stores dashboards and associated Cells
type DashboardStore interface {
// All returns all dashboards in the store
All(context.Context) ([]*Dashboard, error)
// Add creates a new dashboard in the DashboardStore
Add(context.Context, Dashboard) error
Add(context.Context, *Dashboard) error
// Delete the dashboard from the store
Delete(context.Context, Dashboard) error
Delete(context.Context, *Dashboard) error
// Get retrieves Dashboard if `ID` exists
Get(ctx context.Context, ID int) error
Get(ctx context.Context, ID int) (*Dashboard, error)
// Update the dashboard in the store.
Update(context.Context, Dashboard) error
Update(context.Context, *Dashboard) error
}
type Source struct {
ID int // ID is the unique ID of the source
Name string // Name is the user-defined name for the source
Type string // Type specifies which kinds of source (enterprise vs oss)
Username string // Username is the username to connect to the source
Password string // Password is in CLEARTEXT FIXME
URL []string // URL are the connections to the source
Default bool // Default specifies the default source for the application
}
// SourcesStore stores connection information for a `TimeSeries`
type SourcesStore interface {
// All returns all sources in the store
All(context.Context) ([]Source, error)
// Add creates a new source in the SourcesStore and returns Source with ID
Add(context.Context, Source) (Source, error)
// Delete the Source from the store
Delete(context.Context, Source) error
// Get retrieves Source if `ID` exists
Get(ctx context.Context, ID int) (Source, error)
// Update the Source in the store.
Update(context.Context, Source) error
}

View File

@ -20,7 +20,7 @@ paths:
200:
description: Returns the links to the top level endpoints.
schema:
$ref: '#/definitions/Links'
$ref: '#/definitions/Routes'
default:
description: Unexpected internal service error
schema:
@ -730,6 +730,8 @@ paths:
definitions:
Sources:
type: object
required:
- sources
properties:
sources:
type: array
@ -958,6 +960,25 @@ definitions:
type: array
items:
type: string
Routes:
type: object
properties:
users:
description: Location of the users endpoint
type: string
format: url
dashboards:
description: Location of the dashboards endpoint
type: string
format: url
sources:
description: Location of the sources endpoint
type: string
format: url
apps:
description: Location of the apps endpoint
type: string
format: url
Services:
type: object
properties:

View File

@ -27,4 +27,6 @@ type TimeSeries interface {
Query(context.Context, Query) (Response, error)
// MonitoredServices retrieves all services sending monitoring data to this `TimeSeries`
MonitoredServices(context.Context) ([]MonitoredService, error)
// Connect will connect to the time series using the information in `Source`.
Connect(context.Context, *Source) error
}

View File

@ -43,8 +43,8 @@ export const SelectSourcePage = React.createClass({
username: this.sourceUser.value,
password: this.sourcePassword.value,
};
createSource(source).then(() => {
// this.redirectToApp(sourceFromServer)
createSource(source).then(({data: sourceFromServer}) => {
this.redirectToApp(sourceFromServer);
});
},