integrations

pull/342/head
hunterlong 2020-01-02 23:57:42 -08:00
parent 4fcd7d8347
commit 0b93ad4b7a
15 changed files with 170 additions and 40 deletions

View File

@ -18,8 +18,8 @@ package core
import (
"errors"
"fmt"
"github.com/hunterlong/statping/core/integrations"
"github.com/hunterlong/statping/core/notifier"
"github.com/hunterlong/statping/integrations"
"github.com/hunterlong/statping/notifiers"
"github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/types"

View File

@ -20,7 +20,6 @@ import (
"fmt"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
"io/ioutil"
"strconv"
"strings"
"time"
@ -35,12 +34,13 @@ type csvIntegration struct {
var csvIntegrator = &csvIntegration{&types.Integration{
ShortName: "csv",
Name: "CSV File",
Icon: "<i class=\"fas fa-file-csv\"></i>",
Description: "Import multiple services from a CSV file",
Fields: []*types.IntegrationField{
{
Name: "input",
Type: "file",
MimeType: "application/csv",
Name: "input",
Type: "textarea",
Description: "",
},
},
}}
@ -52,12 +52,8 @@ func (t *csvIntegration) Get() *types.Integration {
}
func (t *csvIntegration) List() ([]*types.Service, error) {
path := csvIntegrator.Fields[0].Value.(string)
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
for _, line := range strings.Split(strings.TrimSuffix(string(data), "\n"), "\n") {
data := Value(t, "input").(string)
for _, line := range strings.Split(strings.TrimSuffix(data, "\n"), "\n") {
col := strings.Split(line, ",")
csvData = append(csvData, col)
}

View File

@ -15,11 +15,6 @@ func TestCsvFileIntegration(t *testing.T) {
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) {
services, err := csvIntegrator.List()
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)
})
}

View File

@ -30,6 +30,7 @@ type dockerIntegration struct {
var dockerIntegrator = &dockerIntegration{&types.Integration{
ShortName: "docker",
Name: "Docker",
Icon: "<i class=\"fab fa-docker\"></i>",
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.
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,

View File

@ -8,11 +8,6 @@ import (
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) {
services, err := dockerIntegrator.List()
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)
})
}

View File

@ -30,6 +30,7 @@ func init() {
Integrations = append(Integrations,
csvIntegrator,
dockerIntegrator,
traefikIntegrator,
)
}

View File

@ -2,7 +2,6 @@ package integrations
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
@ -13,9 +12,4 @@ func TestIntegrations(t *testing.T) {
assert.Equal(t, 2, amount)
})
t.Run("Close All Integrations", func(t *testing.T) {
closedAll := CloseAll()
require.Nil(t, closedAll)
})
}

View File

@ -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"`
}

View File

@ -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)
}
})
}

View File

@ -2,7 +2,7 @@ package handlers
import (
"github.com/gorilla/mux"
"github.com/hunterlong/statping/integrations"
"github.com/hunterlong/statping/core/integrations"
"net/http"
)

View File

@ -20,7 +20,7 @@ import (
"fmt"
"github.com/gorilla/mux"
"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/types"
"github.com/hunterlong/statping/utils"

View File

@ -12,6 +12,8 @@
<textarea rows="3" class="form-control" name="{{underscore .Name}}" id="{{underscore .Name}}">{{ .Value }}</textarea>
{{else if eq .Type "text"}}
<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"}}
<input type="number" name="{{underscore .Name}}" class="form-control" value="{{ .Value }}" id="{{underscore .Name}}">
{{else if eq .Type "file"}}

View File

@ -25,7 +25,7 @@
<h6 class="mt-4 text-muted">Integrations</h6>
{{ range .Integrations }}
{{$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}}
</div>
</div>

View File

@ -3,6 +3,7 @@ package types
type Integration struct {
ShortName string `json:"name"`
Name string `json:"full_name"`
Icon string `json:"-"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
Fields []*IntegrationField `json:"fields"`