mirror of
https://github.com/eliasstepanik/ionos.git
synced 2026-01-11 05:28:31 +00:00
parent
c81dabc017
commit
dd3b676071
25
.github/workflows/test.yml
vendored
Normal file
25
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
name: run tests
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16.x
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run linters
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.29
|
||||
- name: Run tests
|
||||
run: go test -v -covermode=count
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Jan Delgado
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
54
README.md
54
README.md
@ -1,6 +1,56 @@
|
||||
# IONOS DNS module for Caddy
|
||||
|
||||
This package contains a DNS provider module for IONOS DNS. It can be used to
|
||||
manage DNS records with IONOS accounts.
|
||||
This package contains a DNS provider module for
|
||||
[Caddy](https://github.com/caddyserver/caddy). It is used to manage DNS records
|
||||
with the [IONOS DNS API](https://developer.hosting.ionos.com/docs/dns) using
|
||||
[libdns-ionos](https://github.com/libdns/ionos)..
|
||||
|
||||
## Caddy module name
|
||||
|
||||
```
|
||||
dns.providers.ionos
|
||||
```
|
||||
|
||||
## Config examples
|
||||
|
||||
To use this module for the ACME DNS challenge, [configure the ACME issuer in your Caddy JSON](https://caddyserver.com/docs/json/apps/tls/automation/policies/issuer/acme/) like so:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": "acme",
|
||||
"challenges": {
|
||||
"dns": {
|
||||
"provider": {
|
||||
"name": "ionos",
|
||||
"api_token": "YOUR_IONOS_AUTH_API_TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
or with the Caddyfile:
|
||||
|
||||
```
|
||||
your.domain.com {
|
||||
respond "Hello World" # replace with whatever config you need...
|
||||
tls {
|
||||
dns ionos {env.YOUR_IONOS_AUTH_API_TOKEN}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can replace `{env.YOUR_IONOS_AUTH_API_TOKEN}` with the actual auth token if
|
||||
you prefer to put it directly in your config instead of an environment
|
||||
variable.
|
||||
|
||||
## Authenticating
|
||||
|
||||
See [the associated README in the libdns package](https://github.com/libdns/ionos#authenticating)
|
||||
for information about obtaining credentials.
|
||||
|
||||
## Author
|
||||
|
||||
(c) Copyright 2021 by Jan Delgado
|
||||
License: MIT
|
||||
|
||||
|
||||
8
go.mod
Normal file
8
go.mod
Normal file
@ -0,0 +1,8 @@
|
||||
module github.com/caddy-dns/ionos
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/caddyserver/caddy/v2 v2.4.3
|
||||
github.com/libdns/ionos v1.0.0
|
||||
)
|
||||
73
ionos.go
Normal file
73
ionos.go
Normal file
@ -0,0 +1,73 @@
|
||||
package ionos
|
||||
|
||||
import (
|
||||
caddy "github.com/caddyserver/caddy/v2"
|
||||
caddyfile "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/libdns/ionos"
|
||||
)
|
||||
|
||||
// Provider wraps the provider implementation as a Caddy module.
|
||||
type Provider struct{ *ionos.Provider }
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(Provider{})
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
func (Provider) CaddyModule() caddy.ModuleInfo {
|
||||
return caddy.ModuleInfo{
|
||||
ID: "dns.providers.ionos",
|
||||
New: func() caddy.Module { return &Provider{new(ionos.Provider)} },
|
||||
}
|
||||
}
|
||||
|
||||
// Before using the provider config, resolve placeholders in the API token.
|
||||
// Implements caddy.Provisioner.
|
||||
func (p *Provider) Provision(ctx caddy.Context) error {
|
||||
repl := caddy.NewReplacer()
|
||||
p.Provider.AuthAPIToken = repl.ReplaceAll(p.Provider.AuthAPIToken, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalCaddyfile sets up the DNS provider from Caddyfile tokens. Syntax:
|
||||
//
|
||||
// ionos [<api_token>] {
|
||||
// api_token <api_token>
|
||||
// }
|
||||
//
|
||||
func (p *Provider) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
for d.Next() {
|
||||
if d.NextArg() {
|
||||
p.Provider.AuthAPIToken = d.Val()
|
||||
}
|
||||
if d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
||||
switch d.Val() {
|
||||
case "api_token":
|
||||
if p.Provider.AuthAPIToken != "" {
|
||||
return d.Err("API token already set")
|
||||
}
|
||||
if d.NextArg() {
|
||||
p.Provider.AuthAPIToken = d.Val()
|
||||
}
|
||||
if d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
default:
|
||||
return d.Errf("unrecognized subdirective '%s'", d.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.Provider.AuthAPIToken == "" {
|
||||
return d.Err("missing API token")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Interface guards
|
||||
var (
|
||||
_ caddyfile.Unmarshaler = (*Provider)(nil)
|
||||
_ caddy.Provisioner = (*Provider)(nil)
|
||||
)
|
||||
81
ionos_test.go
Normal file
81
ionos_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
// some unit/explanatory tests for the IONOS DNS plugin
|
||||
// (c) copyright 2021 by Jan Delgado
|
||||
package ionos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
caddy "github.com/caddyserver/caddy/v2"
|
||||
caddyfile "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/libdns/ionos"
|
||||
)
|
||||
|
||||
func TestUnmarshalCaddyFileExtractsApiToken(t *testing.T) {
|
||||
tests := []string{
|
||||
"ionos token { }",
|
||||
`ionos {
|
||||
api_token token
|
||||
}`}
|
||||
|
||||
for i, tc := range tests {
|
||||
t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) {
|
||||
// given
|
||||
dispenser := caddyfile.NewTestDispenser(tc)
|
||||
p := Provider{&ionos.Provider{}}
|
||||
// when
|
||||
err := p.UnmarshalCaddyfile(dispenser)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Errorf("UnmarshalCaddyfile failed with %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
expected := "token"
|
||||
actual := p.Provider.AuthAPIToken
|
||||
if expected != actual {
|
||||
t.Errorf("Expected AuthAPIToken to be '%s' but got '%s'", expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalCaddyFileReportsErrorConditions(t *testing.T) {
|
||||
|
||||
tests := []struct{ test, expected string }{
|
||||
{"ionos token invalid", "Wrong argument count"},
|
||||
{"ionos { }", "missing API token"},
|
||||
{`ionos token { api_token token }`, "API token already set"},
|
||||
{`ionos { api_token token invalid }`, "Wrong argument count"},
|
||||
{`ionos token { invalid token }`, "unrecognized subdirective 'invalid'"},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) {
|
||||
// given
|
||||
dispenser := caddyfile.NewTestDispenser(tc.test)
|
||||
p := Provider{&ionos.Provider{}}
|
||||
// when
|
||||
err := p.UnmarshalCaddyfile(dispenser)
|
||||
// then
|
||||
if err == nil || !strings.Contains(err.Error(), tc.expected) {
|
||||
t.Errorf("expected error with '%s' but got '%s'", tc.expected, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisionTransformsAPIToken(t *testing.T) {
|
||||
// given
|
||||
expected := "{value}"
|
||||
p := Provider{&ionos.Provider{}}
|
||||
p.Provider.AuthAPIToken = "\\{value\\}"
|
||||
// when
|
||||
_ = p.Provision(caddy.Context{})
|
||||
// then
|
||||
actual := p.Provider.AuthAPIToken
|
||||
if expected != actual {
|
||||
t.Errorf("expected AuthAPIToken to be %s but got %s", expected, actual)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user