mirror of https://github.com/statping/statping
integrations
parent
4fcd7d8347
commit
0b93ad4b7a
|
@ -18,8 +18,8 @@ package core
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/hunterlong/statping/core/integrations"
|
||||||
"github.com/hunterlong/statping/core/notifier"
|
"github.com/hunterlong/statping/core/notifier"
|
||||||
"github.com/hunterlong/statping/integrations"
|
|
||||||
"github.com/hunterlong/statping/notifiers"
|
"github.com/hunterlong/statping/notifiers"
|
||||||
"github.com/hunterlong/statping/source"
|
"github.com/hunterlong/statping/source"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"io/ioutil"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -35,12 +34,13 @@ type csvIntegration struct {
|
||||||
var csvIntegrator = &csvIntegration{&types.Integration{
|
var csvIntegrator = &csvIntegration{&types.Integration{
|
||||||
ShortName: "csv",
|
ShortName: "csv",
|
||||||
Name: "CSV File",
|
Name: "CSV File",
|
||||||
|
Icon: "<i class=\"fas fa-file-csv\"></i>",
|
||||||
Description: "Import multiple services from a CSV file",
|
Description: "Import multiple services from a CSV file",
|
||||||
Fields: []*types.IntegrationField{
|
Fields: []*types.IntegrationField{
|
||||||
{
|
{
|
||||||
Name: "input",
|
Name: "input",
|
||||||
Type: "file",
|
Type: "textarea",
|
||||||
MimeType: "application/csv",
|
Description: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
@ -52,12 +52,8 @@ func (t *csvIntegration) Get() *types.Integration {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *csvIntegration) List() ([]*types.Service, error) {
|
func (t *csvIntegration) List() ([]*types.Service, error) {
|
||||||
path := csvIntegrator.Fields[0].Value.(string)
|
data := Value(t, "input").(string)
|
||||||
data, err := ioutil.ReadFile(path)
|
for _, line := range strings.Split(strings.TrimSuffix(data, "\n"), "\n") {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, line := range strings.Split(strings.TrimSuffix(string(data), "\n"), "\n") {
|
|
||||||
col := strings.Split(line, ",")
|
col := strings.Split(line, ",")
|
||||||
csvData = append(csvData, col)
|
csvData = append(csvData, col)
|
||||||
}
|
}
|
|
@ -15,11 +15,6 @@ func TestCsvFileIntegration(t *testing.T) {
|
||||||
assert.Equal(t, "test_files/example_services.csv", path)
|
assert.Equal(t, "test_files/example_services.csv", path)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("CSV Open File", func(t *testing.T) {
|
|
||||||
err := csvIntegrator.Open()
|
|
||||||
require.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("List Services from CSV File", func(t *testing.T) {
|
t.Run("List Services from CSV File", func(t *testing.T) {
|
||||||
services, err := csvIntegrator.List()
|
services, err := csvIntegrator.List()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
@ -37,9 +32,4 @@ func TestCsvFileIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Close CSV", func(t *testing.T) {
|
|
||||||
err := csvIntegrator.Close()
|
|
||||||
require.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -30,6 +30,7 @@ type dockerIntegration struct {
|
||||||
var dockerIntegrator = &dockerIntegration{&types.Integration{
|
var dockerIntegrator = &dockerIntegration{&types.Integration{
|
||||||
ShortName: "docker",
|
ShortName: "docker",
|
||||||
Name: "Docker",
|
Name: "Docker",
|
||||||
|
Icon: "<i class=\"fab fa-docker\"></i>",
|
||||||
Description: `Import multiple services from Docker by attaching the unix socket to Statping.
|
Description: `Import multiple services from Docker by attaching the unix socket to Statping.
|
||||||
You can also do this in Docker by setting <u>-v /var/run/docker.sock:/var/run/docker.sock</u> in the Statping Docker container.
|
You can also do this in Docker by setting <u>-v /var/run/docker.sock:/var/run/docker.sock</u> in the Statping Docker container.
|
||||||
All of the containers with open TCP/UDP ports will be listed for you to choose which services you want to add. If you running Statping inside of a container,
|
All of the containers with open TCP/UDP ports will be listed for you to choose which services you want to add. If you running Statping inside of a container,
|
|
@ -8,11 +8,6 @@ import (
|
||||||
|
|
||||||
func TestDockerIntegration(t *testing.T) {
|
func TestDockerIntegration(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Docker Open containers", func(t *testing.T) {
|
|
||||||
err := dockerIntegrator.Open()
|
|
||||||
require.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("List Services from Docker", func(t *testing.T) {
|
t.Run("List Services from Docker", func(t *testing.T) {
|
||||||
services, err := dockerIntegrator.List()
|
services, err := dockerIntegrator.List()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
@ -27,9 +22,4 @@ func TestDockerIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Close Docker", func(t *testing.T) {
|
|
||||||
err := dockerIntegrator.Close()
|
|
||||||
require.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -30,6 +30,7 @@ func init() {
|
||||||
Integrations = append(Integrations,
|
Integrations = append(Integrations,
|
||||||
csvIntegrator,
|
csvIntegrator,
|
||||||
dockerIntegrator,
|
dockerIntegrator,
|
||||||
|
traefikIntegrator,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,9 +12,4 @@ func TestIntegrations(t *testing.T) {
|
||||||
assert.Equal(t, 2, amount)
|
assert.Equal(t, 2, amount)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Close All Integrations", func(t *testing.T) {
|
|
||||||
closedAll := CloseAll()
|
|
||||||
require.Nil(t, closedAll)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
// Statping
|
||||||
|
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||||
|
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||||
|
//
|
||||||
|
// https://github.com/hunterlong/statping
|
||||||
|
//
|
||||||
|
// The licenses for most software and other practical works are designed
|
||||||
|
// to take away your freedom to share and change the works. By contrast,
|
||||||
|
// the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
// share and change all versions of a program--to make sure it remains free
|
||||||
|
// software for all its users.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/hunterlong/statping/types"
|
||||||
|
"github.com/hunterlong/statping/utils"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type traefikIntegration struct {
|
||||||
|
*types.Integration
|
||||||
|
}
|
||||||
|
|
||||||
|
var traefikIntegrator = &traefikIntegration{&types.Integration{
|
||||||
|
ShortName: "traefik",
|
||||||
|
Name: "Traefik",
|
||||||
|
Icon: "<i class=\"fas fa-network-wired\"></i>",
|
||||||
|
Description: ``,
|
||||||
|
Fields: []*types.IntegrationField{
|
||||||
|
{
|
||||||
|
Name: "endpoint",
|
||||||
|
Description: "The URL for the traefik API Endpoint",
|
||||||
|
Type: "text",
|
||||||
|
Value: "http://localhost:8080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "username",
|
||||||
|
Description: "Username for HTTP Basic Authentication",
|
||||||
|
Type: "text",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "password",
|
||||||
|
Description: "Password for HTTP Basic Authentication",
|
||||||
|
Type: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
func (t *traefikIntegration) Get() *types.Integration {
|
||||||
|
return t.Integration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *traefikIntegration) List() ([]*types.Service, error) {
|
||||||
|
var err error
|
||||||
|
var services []*types.Service
|
||||||
|
|
||||||
|
endpoint := Value(t, "endpoint").(string)
|
||||||
|
|
||||||
|
httpServices, err := fetchMethod(endpoint, "http")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
services = append(services, httpServices...)
|
||||||
|
|
||||||
|
tcpServices, err := fetchMethod(endpoint, "tcp")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
services = append(services, tcpServices...)
|
||||||
|
|
||||||
|
return services, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchMethod(endpoint, method string) ([]*types.Service, error) {
|
||||||
|
var traefikServices []traefikService
|
||||||
|
var services []*types.Service
|
||||||
|
d, _, err := utils.HttpRequest(endpoint+"/api/"+method+"/services", "GET", nil, []string{}, nil, 10*time.Second, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(d, &traefikServices); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, s := range traefikServices {
|
||||||
|
log.Infoln(s)
|
||||||
|
|
||||||
|
for _, l := range s.LoadBalancer.Servers {
|
||||||
|
|
||||||
|
url, err := url.Parse(l.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
service := &types.Service{
|
||||||
|
Name: s.Name,
|
||||||
|
Domain: url.Hostname(),
|
||||||
|
Port: int(utils.ToInt(url.Port())),
|
||||||
|
Type: method,
|
||||||
|
Interval: 60,
|
||||||
|
Timeout: 2,
|
||||||
|
}
|
||||||
|
services = append(services, service)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return services, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type traefikService struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
UsedBy []string `json:"usedBy"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
LoadBalancer struct {
|
||||||
|
Servers []struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"servers"`
|
||||||
|
PassHostHeader bool `json:"passHostHeader"`
|
||||||
|
} `json:"loadBalancer,omitempty"`
|
||||||
|
ServerStatus struct {
|
||||||
|
HTTP17217128080 string `json:"http://172.17.1.2:8080"`
|
||||||
|
} `json:"serverStatus,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTraefikIntegration(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("List Services from Traefik", func(t *testing.T) {
|
||||||
|
services, err := traefikIntegrator.List()
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.NotEqual(t, 0, len(services))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Confirm Services from Traefik", func(t *testing.T) {
|
||||||
|
services, err := traefikIntegrator.List()
|
||||||
|
require.Nil(t, err)
|
||||||
|
for _, s := range services {
|
||||||
|
t.Log(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/hunterlong/statping/integrations"
|
"github.com/hunterlong/statping/core/integrations"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/hunterlong/statping/core"
|
"github.com/hunterlong/statping/core"
|
||||||
"github.com/hunterlong/statping/integrations"
|
"github.com/hunterlong/statping/core/integrations"
|
||||||
"github.com/hunterlong/statping/source"
|
"github.com/hunterlong/statping/source"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
<textarea rows="3" class="form-control" name="{{underscore .Name}}" id="{{underscore .Name}}">{{ .Value }}</textarea>
|
<textarea rows="3" class="form-control" name="{{underscore .Name}}" id="{{underscore .Name}}">{{ .Value }}</textarea>
|
||||||
{{else if eq .Type "text"}}
|
{{else if eq .Type "text"}}
|
||||||
<input type="text" name="{{underscore .Name}}" class="form-control" value="{{ .Value }}" id="{{underscore .Name}}">
|
<input type="text" name="{{underscore .Name}}" class="form-control" value="{{ .Value }}" id="{{underscore .Name}}">
|
||||||
|
{{else if eq .Type "password"}}
|
||||||
|
<input type="password" name="{{underscore .Name}}" class="form-control" value="{{ .Value }}" id="{{underscore .Name}}">
|
||||||
{{else if eq .Type "integer"}}
|
{{else if eq .Type "integer"}}
|
||||||
<input type="number" name="{{underscore .Name}}" class="form-control" value="{{ .Value }}" id="{{underscore .Name}}">
|
<input type="number" name="{{underscore .Name}}" class="form-control" value="{{ .Value }}" id="{{underscore .Name}}">
|
||||||
{{else if eq .Type "file"}}
|
{{else if eq .Type "file"}}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<h6 class="mt-4 text-muted">Integrations</h6>
|
<h6 class="mt-4 text-muted">Integrations</h6>
|
||||||
{{ range .Integrations }}
|
{{ range .Integrations }}
|
||||||
{{$i := .Get}}
|
{{$i := .Get}}
|
||||||
<a class="nav-link text-capitalize" id="v-pills-integration-{{underscore $i.ShortName}}-tab" data-toggle="pill" href="#v-pills-integration-{{underscore $i.ShortName}}" role="tab" aria-controls="v-pills-integration-{{underscore $i.ShortName}}" aria-selected="false">{{$i.Name}}</a>
|
<a class="nav-link text-capitalize" id="v-pills-integration-{{underscore $i.ShortName}}-tab" data-toggle="pill" href="#v-pills-integration-{{underscore $i.ShortName}}" role="tab" aria-controls="v-pills-integration-{{underscore $i.ShortName}}" aria-selected="false">{{safe $i.Icon}} {{$i.Name}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types
|
||||||
type Integration struct {
|
type Integration struct {
|
||||||
ShortName string `json:"name"`
|
ShortName string `json:"name"`
|
||||||
Name string `json:"full_name"`
|
Name string `json:"full_name"`
|
||||||
|
Icon string `json:"-"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Fields []*IntegrationField `json:"fields"`
|
Fields []*IntegrationField `json:"fields"`
|
||||||
|
|
Loading…
Reference in New Issue