Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
|
db65d47ea9 | |
|
8c7ccf7e9f | |
|
0e4ee6fcf8 | |
|
1f47ca4ee6 | |
|
fefb874f95 | |
|
804f9a337c | |
|
8c6189b4b8 | |
|
4acbfefd43 |
|
@ -1,7 +1,7 @@
|
||||||
##
|
##
|
||||||
# Compile application
|
# Compile application
|
||||||
##
|
##
|
||||||
FROM golang:latest AS build-env
|
FROM docker.io/library/golang:alpine AS build-env
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
# ge dependencies
|
# ge dependencies
|
||||||
|
@ -14,8 +14,7 @@ RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o oven-exporter
|
||||||
# Build Image
|
# Build Image
|
||||||
##
|
##
|
||||||
FROM scratch
|
FROM scratch
|
||||||
|
COPY --from=build-env ["/etc/ssl/cert.pem", "/etc/ssl/certs/ca-certificates.crt"]
|
||||||
COPY --from=build-env /app/oven-exporter /oven-exporter
|
COPY --from=build-env /app/oven-exporter /oven-exporter
|
||||||
COPY --from=build-env /app/config_example.toml /config.toml
|
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
ENTRYPOINT ["/oven-exporter"]
|
ENTRYPOINT ["/oven-exporter", "-c", ""]
|
|
@ -0,0 +1,59 @@
|
||||||
|
== Oven-Exporter
|
||||||
|
|
||||||
|
An Prometheus Exporter for OvenMediaEngine
|
||||||
|
|
||||||
|
(it provides also a small API-Client for OvenMediaEngine) Be welcome to improve it.
|
||||||
|
|
||||||
|
=== Configure OvenMediaEngine
|
||||||
|
|
||||||
|
This Exporter use the REST-API of OvenMediaEngine, to setting it up, that a look in there Documentation https://airensoft.gitbook.io/ovenmediaengine/rest-api[OvenMediaEngine REST-API].
|
||||||
|
|
||||||
|
=== Setup Exporter
|
||||||
|
|
||||||
|
==== Compile
|
||||||
|
|
||||||
|
Install https://golang.org/doc/install[golang].
|
||||||
|
|
||||||
|
Run: `go install -v codeberg.org/Mediathek/oven-exporter@latest`
|
||||||
|
|
||||||
|
==== Configuration
|
||||||
|
|
||||||
|
Read comments in config_example.toml for more information.
|
||||||
|
|
||||||
|
Maybe a good place to store this file is: `/etc/ovenmediaengine/exporter.conf`
|
||||||
|
|
||||||
|
OR use env variables:
|
||||||
|
|
||||||
|
....
|
||||||
|
OVEN_E_LISTEN=:8080
|
||||||
|
OVEN_E_API__URL=http://1.2.3.4:8081
|
||||||
|
OVEN_E_API__TOKEN=ome-access-token
|
||||||
|
OVEN_E_API__DEFAULT_VHOST=
|
||||||
|
OVEN_E_API__DEFAULT_APP=
|
||||||
|
....
|
||||||
|
|
||||||
|
(File read could be disabled by call `oven-exporter -c ''`
|
||||||
|
|
||||||
|
==== Startup
|
||||||
|
|
||||||
|
Create a systemd.service file e.g. under `/etc/systemd/system/oven-exporter.service` with maybe a content like this:
|
||||||
|
|
||||||
|
[source,ini]
|
||||||
|
----
|
||||||
|
[Unit]
|
||||||
|
Description = Prometheus exporter for OvenMediaEngine
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/oven-exporter -c /etc/ovenmediaengine/exporter.conf
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5s
|
||||||
|
Environment=PATH=/usr/bin:/usr/local/bin
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
----
|
||||||
|
|
||||||
|
PS: maybe you need to adjust the binary path and configuration path.
|
||||||
|
|
||||||
|
Start and enable on boot: `systemctl enable --now oven-exporter.service`
|
47
README.md
47
README.md
|
@ -1,47 +0,0 @@
|
||||||
# Oven-Exporter
|
|
||||||
An Prometheus Exporter for OvenMediaEngine
|
|
||||||
|
|
||||||
(it provides also a small API-Client for OvenMediaEngine)
|
|
||||||
Be welcome to improve it.
|
|
||||||
|
|
||||||
## Configure OvenMediaEngine
|
|
||||||
|
|
||||||
This Exporter use the REST-API of OvenMediaEngine,
|
|
||||||
to setting it up, that a look in there Documentation [OvenMediaEngine REST-API](
|
|
||||||
https://airensoft.gitbook.io/ovenmediaengine/rest-api).
|
|
||||||
|
|
||||||
## Setup Exporter
|
|
||||||
|
|
||||||
### Compile
|
|
||||||
|
|
||||||
Install [golang](https://golang.org/doc/install).
|
|
||||||
|
|
||||||
Run:
|
|
||||||
`go install -v dev.sum7.eu/genofire/oven-exporter@latest`
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
Read comments in [config_example.toml](config_example.toml) for more information.
|
|
||||||
|
|
||||||
Maybe a good place to store this file is: `/etc/ovenmediaengine/exporter.conf`
|
|
||||||
|
|
||||||
### Startup
|
|
||||||
Create a systemd.service file e.g. under `/etc/systemd/system/oven-exporter.service` with maybe a content like this:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[Unit]
|
|
||||||
Description = Prometheus exporter for OvenMediaEngine
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
ExecStart=/usr/local/bin/oven-exporter -c /etc/ovenmediaengine/exporter.conf
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5s
|
|
||||||
Environment=PATH=/usr/bin:/usr/local/bin
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
PS: maybe you need to adjust the binary path and configuration path.
|
|
||||||
|
|
||||||
Start and enable on boot:
|
|
||||||
`systemctl enable --now oven-exporter.service`
|
|
|
@ -4,10 +4,10 @@ import "encoding/base64"
|
||||||
|
|
||||||
// A Client for the API
|
// A Client for the API
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Token string `toml:"token"`
|
Token string `config:"token"`
|
||||||
URL string `toml:"url"`
|
URL string `config:"url"`
|
||||||
DefaultVHost string `toml:"default_vhost"`
|
DefaultVHost string `config:"default_vhost"`
|
||||||
DefaultApp string `toml:"default_app"`
|
DefaultApp string `config:"default_app"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// New Client from host and token
|
// New Client from host and token
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
name: oven-exporter
|
||||||
|
title: Oven Exporter
|
||||||
|
# use from git tag
|
||||||
|
version:
|
||||||
|
v(?<version>+({0..9}).+({0..9}).+({0..9})): $<version>
|
||||||
|
main: latest
|
||||||
|
|
||||||
|
nav:
|
||||||
|
- "modules/ROOT/nav.adoc"
|
|
@ -0,0 +1 @@
|
||||||
|
../../../../README.adoc
|
16
go.mod
16
go.mod
|
@ -1,10 +1,16 @@
|
||||||
module dev.sum7.eu/genofire/oven-exporter
|
module codeberg.org/Mediathek/oven-exporter
|
||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
dev.sum7.eu/genofire/golang-lib v0.0.0-20210719163544-fb766ca32b7c
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.10.0
|
github.com/knadh/koanf v1.5.0
|
||||||
go.uber.org/zap v1.13.0
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
github.com/prometheus/client_golang v1.17.0
|
||||||
|
github.com/prometheus/client_model v0.5.0 // indirect
|
||||||
|
github.com/prometheus/common v0.45.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.26.0
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Policy struct {
|
||||||
|
URLExpire int64 `json:"url_expire"`
|
||||||
|
URLActivate int64 `json:"url_activate,omitempty"`
|
||||||
|
StreamExpire int64 `json:"stream_expire,omitempty"`
|
||||||
|
AllowIP string `json:"allow_ip,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Policy) Encode() (string, error) {
|
||||||
|
str, err := json.Marshal(p)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.RawStdEncoding.EncodeToString(str), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignEncodedPolicy(u *url.URL, secretKey string) string {
|
||||||
|
hasher := hmac.New(sha1.New, []byte(secretKey))
|
||||||
|
hasher.Write([]byte(u.String()))
|
||||||
|
return base64.RawURLEncoding.EncodeToString(hasher.Sum(nil))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Policy) SignWithQuery(u *url.URL, secretKey, encodeQuery string) (string, error) {
|
||||||
|
encode, err := p.Encode()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
query := u.Query()
|
||||||
|
query.Add(encodeQuery, encode)
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
return SignEncodedPolicy(u, secretKey), nil
|
||||||
|
}
|
||||||
|
func (p Policy) Sign(u *url.URL, secretKey string) (string, error) {
|
||||||
|
return p.SignWithQuery(u, secretKey, "policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Policy) SignURLWithQuery(u *url.URL, secretKey, encodeQuery, signatureQuery string) error {
|
||||||
|
encode, err := p.Encode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
query := u.Query()
|
||||||
|
query.Add(encodeQuery, encode)
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
signature := SignEncodedPolicy(u, secretKey)
|
||||||
|
query.Add(signatureQuery, signature)
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (p Policy) SignURL(u *url.URL, secretKey string) error {
|
||||||
|
return p.SignURLWithQuery(u, secretKey, "policy", "signature")
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
// https://airensoft.gitbook.io/ovenmediaengine/access-control/signedpolicy
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
examplePolicyEncode = "eyJ1cmxfZXhwaXJlIjoxMzk5NzIxNTgxfQ"
|
||||||
|
exampleSecretKey = "1kU^b6"
|
||||||
|
exampleURL = "ws://192.168.0.100:3333/app/stream"
|
||||||
|
exampleSignature = "dvVdBpoxAeCPl94Kt5RoiqLI0YE"
|
||||||
|
exampleURLWithSignatureAndPolicy = "ws://192.168.0.100/app/stream?policy=eyJ1cmxfZXhwaXJlIjoxMzk5NzIxNTgxfQ&signature=dvVdBpoxAeCPl94Kt5RoiqLI0YE"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
examplePolicy = Policy{
|
||||||
|
URLExpire: 1399721581,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPolicyEncode(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
encode, err := examplePolicy.Encode()
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(examplePolicyEncode, encode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPolicySign(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
u, err := url.Parse(exampleURL)
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
sign, err := examplePolicy.Sign(u, exampleSecretKey)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(exampleSignature, sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPolicySignURL(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
u, err := url.Parse(exampleURL)
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
err = examplePolicy.SignURL(u, exampleSecretKey)
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
// drop port -> is not part of example
|
||||||
|
u.Host = u.Hostname()
|
||||||
|
|
||||||
|
assert.Equal(exampleURLWithSignatureAndPolicy, u.String())
|
||||||
|
}
|
53
main.go
53
main.go
|
@ -3,34 +3,71 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"dev.sum7.eu/genofire/golang-lib/file"
|
"github.com/knadh/koanf"
|
||||||
|
"github.com/knadh/koanf/parsers/json"
|
||||||
|
"github.com/knadh/koanf/parsers/toml"
|
||||||
|
"github.com/knadh/koanf/parsers/yaml"
|
||||||
|
"github.com/knadh/koanf/providers/env"
|
||||||
|
"github.com/knadh/koanf/providers/file"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"dev.sum7.eu/genofire/oven-exporter/api"
|
"codeberg.org/Mediathek/oven-exporter/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var configExtParser = map[string]koanf.Parser{
|
||||||
|
".json": json.Parser(),
|
||||||
|
".toml": toml.Parser(),
|
||||||
|
".yaml": yaml.Parser(),
|
||||||
|
".yml": yaml.Parser(),
|
||||||
|
}
|
||||||
|
|
||||||
type configData struct {
|
type configData struct {
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
Log *zap.Config `toml:"log"`
|
Log *zap.Config `config:"log"`
|
||||||
API *api.Client `toml:"api"`
|
API api.Client `config:"api"`
|
||||||
Listen string `toml:"listen"`
|
Listen string `config:"listen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
configPath := "config.toml"
|
configPath := "config.toml"
|
||||||
|
|
||||||
log, _ := zap.NewProduction()
|
log, _ := zap.NewProduction()
|
||||||
|
|
||||||
flag.StringVar(&configPath, "c", configPath, "path to configuration file")
|
flag.StringVar(&configPath, "c", configPath, "path to configuration file")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
k := koanf.New("/")
|
||||||
|
|
||||||
|
if configPath != "" {
|
||||||
|
fileExt := filepath.Ext(configPath)
|
||||||
|
parser, ok := configExtParser[fileExt]
|
||||||
|
if !ok {
|
||||||
|
log.Panic("unsupported file extension:",
|
||||||
|
zap.String("config-path", configPath),
|
||||||
|
zap.String("file-ext", fileExt),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if err := k.Load(file.Provider(configPath), parser); err != nil {
|
||||||
|
log.Panic("load file config:", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := k.Load(env.Provider("OVEN_E_", "/", func(s string) string {
|
||||||
|
return strings.Replace(strings.ToLower(
|
||||||
|
strings.TrimPrefix(s, "OVEN_E_")), "__", "/", -1)
|
||||||
|
}), nil); err != nil {
|
||||||
|
log.Panic("load env:", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
config := &configData{}
|
config := &configData{}
|
||||||
if err := file.ReadTOML(configPath, config); err != nil {
|
if err := k.UnmarshalWithConf("", &config, koanf.UnmarshalConf{Tag: "config"}); err != nil {
|
||||||
log.Panic("open config file", zap.Error(err))
|
log.Panic("reading config", zap.Error(err))
|
||||||
}
|
}
|
||||||
if config.Log != nil {
|
if config.Log != nil {
|
||||||
l, err := config.Log.Build()
|
l, err := config.Log.Build()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"dev.sum7.eu/genofire/oven-exporter/api"
|
"codeberg.org/Mediathek/oven-exporter/api"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue