Skip to content

Commit

Permalink
v0.5.0-rc4: initial support for ovh, provider generator implementatio…
Browse files Browse the repository at this point in the history
…n update, replaced all interface{} to any
  • Loading branch information
yusing committed Sep 17, 2024
1 parent 82f0637 commit 21fcceb
Show file tree
Hide file tree
Showing 21 changed files with 286 additions and 64 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ See [providers.example.yml](providers.example.yml) for examples

- Cert "renewal" is actually obtaining a new cert instead of renewing the existing one

- `autocert` config is not hot-reloadable

[🔼Back to top](#table-of-content)

## Build it yourself
Expand Down
33 changes: 27 additions & 6 deletions docs/dns_providers.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Supported DNS Providers

<!-- TOC -->
- [Cloudflare](#cloudflare)
- [CloudDNS](#clouddns)
- [DuckDNS](#duckdns)
- [Implement other DNS providers](#implement-other-dns-providers)
<!-- /TOC -->

- [Supported DNS Providers](#supported-dns-providers)
- [Cloudflare](#cloudflare)
- [CloudDNS](#clouddns)
- [DuckDNS](#duckdns)
- [OVHCloud](#ovhcloud)
- [Implement other DNS providers](#implement-other-dns-providers)

## Cloudflare

Expand All @@ -23,10 +25,29 @@ Follow [this guide](https://cloudkul.com/blog/automcatic-renew-and-generate-ssl-

## DuckDNS

`token`: DuckDNS Token
- `token`: DuckDNS Token

Tested by [earvingad](https://github.com/earvingad)

## OVHCloud

_Note, `application_key` and `oauth2_config` **CANNOT** be used together_

- `api_endpoint`: Endpoint URL, or one of
- `ovh-eu`,
- `ovh-ca`,
- `ovh-us`,
- `kimsufi-eu`,
- `kimsufi-ca`,
- `soyoustart-eu`,
- `soyoustart-ca`
- `application_secret`
- `application_key`
- `consumer_key`
- `oauth2_config`: Client ID and Client Secret
- `client_id`
- `client_secret`

## Implement other DNS providers

See [add_dns_provider.md](docs/add_dns_provider.md)
2 changes: 1 addition & 1 deletion go.work
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
go 1.22
go 1.22.0

toolchain go1.23.1

Expand Down
78 changes: 77 additions & 1 deletion schema/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"title": "DNS Challenge Provider",
"default": "local",
"type": "string",
"enum": ["local", "cloudflare", "clouddns", "duckdns"]
"enum": ["local", "cloudflare", "clouddns", "duckdns", "ovh"]
},
"options": {
"title": "Provider specific options",
Expand Down Expand Up @@ -135,6 +135,82 @@
}
}
}
},
{
"if": {
"properties": {
"provider": {
"const": "ovh"
}
}
},
"then": {
"properties": {
"options": {
"required": ["application_secret", "consumer_key"],
"additionalProperties": false,
"oneOf": [
{
"required": ["application_key"]
},
{
"required": ["oauth2_config"]
}
],
"properties": {
"api_endpoint": {
"description": "OVH API endpoint",
"default": "ovh-eu",
"anyOf": [
{
"enum": [
"ovh-eu",
"ovh-ca",
"ovh-us",
"kimsufi-eu",
"kimsufi-ca",
"soyoustart-eu",
"soyoustart-ca"
]
},
{
"type": "string",
"format": "uri"
}
]
},
"application_secret": {
"description": "OVH Application Secret",
"type": "string"
},
"consumer_key": {
"description": "OVH Consumer Key",
"type": "string"
},
"application_key": {
"description": "OVH Application Key",
"type": "string"
},
"oauth2_config": {
"description": "OVH OAuth2 config",
"type": "object",
"additionalProperties": false,
"properties": {
"client_id": {
"description": "OVH Client ID",
"type": "string"
},
"client_secret": {
"description": "OVH Client Secret",
"type": "string"
}
},
"required": ["client_id", "client_secret"]
}
}
}
}
}
}
]
},
Expand Down
2 changes: 1 addition & 1 deletion src/api/v1/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func Stats(cfg *config.Config, w http.ResponseWriter, r *http.Request) {
stats := map[string]interface{}{
stats := map[string]any{
"proxies": cfg.Statistics(),
"uptime": utils.FormatDuration(server.GetProxyServer().Uptime()),
}
Expand Down
3 changes: 3 additions & 0 deletions src/autocert/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/clouddns"
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
"github.com/go-acme/lego/v4/providers/dns/duckdns"
"github.com/go-acme/lego/v4/providers/dns/ovh"
"github.com/sirupsen/logrus"
)

Expand All @@ -19,13 +20,15 @@ const (
ProviderCloudflare = "cloudflare"
ProviderClouddns = "clouddns"
ProviderDuckdns = "duckdns"
ProviderOVH = "ovh"
)

var providersGenMap = map[string]ProviderGenerator{
ProviderLocal: providerGenerator(NewDummyDefaultConfig, NewDummyDNSProviderConfig),
ProviderCloudflare: providerGenerator(cloudflare.NewDefaultConfig, cloudflare.NewDNSProviderConfig),
ProviderClouddns: providerGenerator(clouddns.NewDefaultConfig, clouddns.NewDNSProviderConfig),
ProviderDuckdns: providerGenerator(duckdns.NewDefaultConfig, duckdns.NewDNSProviderConfig),
ProviderOVH: providerGenerator(ovh.NewDefaultConfig, ovh.NewDNSProviderConfig),
}

var logger = logrus.WithField("module", "autocert")
12 changes: 1 addition & 11 deletions src/autocert/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,23 +272,13 @@ func getCertExpiries(cert *tls.Certificate) (CertExpiries, E.NestedError) {
return r, E.Nil()
}

func setOptions[T interface{}](cfg *T, opt M.AutocertProviderOpt) E.NestedError {
for k, v := range opt {
err := U.SetFieldFromSnake(cfg, k, v)
if err.HasError() {
return E.Failure("set autocert option").Subject(k).With(err)
}
}
return E.Nil()
}

func providerGenerator[CT any, PT challenge.Provider](
defaultCfg func() *CT,
newProvider func(*CT) (PT, error),
) ProviderGenerator {
return func(opt M.AutocertProviderOpt) (challenge.Provider, E.NestedError) {
cfg := defaultCfg()
err := setOptions(cfg, opt)
err := U.Deserialize(opt, cfg)
if err.HasError() {
return nil, err
}
Expand Down
49 changes: 49 additions & 0 deletions src/autocert/provider_test/ovh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package provider_test

import (
"testing"

"github.com/go-acme/lego/v4/providers/dns/ovh"
. "github.com/yusing/go-proxy/utils"
"gopkg.in/yaml.v3"
)

// type Config struct {
// APIEndpoint string

// ApplicationKey string
// ApplicationSecret string
// ConsumerKey string

// OAuth2Config *OAuth2Config

// PropagationTimeout time.Duration
// PollingInterval time.Duration
// TTL int
// HTTPClient *http.Client
// }

func TestOVH(t *testing.T) {
cfg := &ovh.Config{}
testYaml := `
api_endpoint: https://eu.api.ovh.com
application_key: <application_key>
application_secret: <application_secret>
consumer_key: <consumer_key>
oauth2_config:
client_id: <client_id>
client_secret: <client_secret>
`
cfgExpected := &ovh.Config{
APIEndpoint: "https://eu.api.ovh.com",
ApplicationKey: "<application_key>",
ApplicationSecret: "<application_secret>",
ConsumerKey: "<consumer_key>",
OAuth2Config: &ovh.OAuth2Config{ClientID: "<client_id>", ClientSecret: "<client_secret>"},
}
testYaml = testYaml[1:] // remove first \n
opt := make(map[string]any)
ExpectNoError(t, yaml.Unmarshal([]byte(testYaml), opt))
ExpectNoError(t, Deserialize(opt, cfg))
ExpectEqual(t, cfg, cfgExpected)
}
10 changes: 5 additions & 5 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (cfg *Config) RoutesByAlias() map[string]U.SerializedObject {
prName := p.GetName()
p.GetCurrentRoutes().EachKV(func(a string, r R.Route) {
obj, err := U.Serialize(r)
if err != nil {
if err.HasError() {
cfg.l.Error(err)
return
}
Expand All @@ -114,13 +114,13 @@ func (cfg *Config) RoutesByAlias() map[string]U.SerializedObject {
return routes
}

func (cfg *Config) Statistics() map[string]interface{} {
func (cfg *Config) Statistics() map[string]any {
nTotalStreams := 0
nTotalRPs := 0
providerStats := make(map[string]interface{})
providerStats := make(map[string]any)

cfg.proxyProviders.Each(func(p *PR.Provider) {
stats := make(map[string]interface{})
stats := make(map[string]any)
nStreams := 0
nRPs := 0
p.GetCurrentRoutes().EachKV(func(a string, r R.Route) {
Expand All @@ -141,7 +141,7 @@ func (cfg *Config) Statistics() map[string]interface{} {
providerStats[p.GetName()] = stats
})

return map[string]interface{}{
return map[string]any{
"num_total_streams": nTotalStreams,
"num_total_reverse_proxies": nTotalRPs,
"providers": providerStats,
Expand Down
2 changes: 1 addition & 1 deletion src/docker/homepage_label.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type (
Icon string
Category string
Description string
WidgetConfig map[string]interface{}
WidgetConfig map[string]any
}
)

Expand Down
14 changes: 7 additions & 7 deletions src/docker/label_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestHomePageLabel(t *testing.T) {
field := "ip"
v := "bar"
pl, err := ParseLabel(makeLabel(NSHomePage, alias, field), v)
ExpectErrNil(t, err)
ExpectNoError(t, err)
if pl.Target != alias {
t.Errorf("Expected alias=%s, got %s", alias, pl.Target)
}
Expand All @@ -34,7 +34,7 @@ func TestHomePageLabel(t *testing.T) {
func TestStringProxyLabel(t *testing.T) {
v := "bar"
pl, err := ParseLabel(makeLabel(NSProxy, "foo", "ip"), v)
ExpectErrNil(t, err)
ExpectNoError(t, err)
ExpectEqual(t, pl.Value, v)
}

Expand All @@ -52,7 +52,7 @@ func TestBoolProxyLabelValid(t *testing.T) {

for k, v := range tests {
pl, err := ParseLabel(makeLabel(NSProxy, "foo", "no_tls_verify"), k)
ExpectErrNil(t, err)
ExpectNoError(t, err)
ExpectEqual(t, pl.Value, v)
}
}
Expand All @@ -78,7 +78,7 @@ X-Custom-Header2: boo`
}

pl, err := ParseLabel(makeLabel(NSProxy, "foo", "set_headers"), v)
ExpectErrNil(t, err)
ExpectNoError(t, err)
hGot := ExpectType[map[string]string](t, pl.Value)
if hGot != nil && !reflect.DeepEqual(h, hGot) {
t.Errorf("Expected %v, got %v", h, hGot)
Expand Down Expand Up @@ -109,7 +109,7 @@ func TestHideHeadersProxyLabel(t *testing.T) {
`
v = strings.TrimPrefix(v, "\n")
pl, err := ParseLabel(makeLabel(NSProxy, "foo", "hide_headers"), v)
ExpectErrNil(t, err)
ExpectNoError(t, err)
sGot := ExpectType[[]string](t, pl.Value)
sWant := []string{"X-Custom-Header1", "X-Custom-Header2", "X-Custom-Header3"}
if sGot != nil {
Expand All @@ -120,7 +120,7 @@ func TestHideHeadersProxyLabel(t *testing.T) {
func TestCommaSepProxyLabelSingle(t *testing.T) {
v := "a"
pl, err := ParseLabel("proxy.aliases", v)
ExpectErrNil(t, err)
ExpectNoError(t, err)
sGot := ExpectType[[]string](t, pl.Value)
sWant := []string{"a"}
if sGot != nil {
Expand All @@ -132,7 +132,7 @@ func TestCommaSepProxyLabelSingle(t *testing.T) {
func TestCommaSepProxyLabelMulti(t *testing.T) {
v := "X-Custom-Header1, X-Custom-Header2,X-Custom-Header3"
pl, err := ParseLabel("proxy.aliases", v)
ExpectErrNil(t, err)
ExpectNoError(t, err)
sGot := ExpectType[[]string](t, pl.Value)
sWant := []string{"X-Custom-Header1", "X-Custom-Header2", "X-Custom-Header3"}
if sGot != nil {
Expand Down
Loading

0 comments on commit 21fcceb

Please sign in to comment.