1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

NEW PROVIDER: GANDI_V5 (deprecates GANDI) (#572)

* GANDI_v5: Add Registrar support
* Add GANDI deprecation warning
* vendor github.com/tiramiseb/go-gandi
This commit is contained in:
Tom Limoncelli
2020-01-20 14:13:32 -05:00
committed by GitHub
parent 2c6878237e
commit f6ce421fdd
35 changed files with 2047 additions and 385 deletions

View File

@ -113,6 +113,17 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
return Error(t, err, append([]interface{}{msg}, args...)...)
}
// Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
}
// Exactlyf asserts that two objects are equal in value and type.
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
@ -157,6 +168,31 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool
return FileExists(t, path, append([]interface{}{msg}, args...)...)
}
// Greaterf asserts that the first element is greater than the second
//
// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
//
// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
@ -289,6 +325,14 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// YAMLEqf asserts that two YAML strings are equivalent.
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
@ -300,6 +344,31 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
return Len(t, object, length, append([]interface{}{msg}, args...)...)
}
// Lessf asserts that the first element is less than the second
//
// assert.Lessf(t, 1, 2, "error message %s", "formatted")
// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
// assert.Lessf(t, "a", "b", "error message %s", "formatted")
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// LessOrEqualf asserts that the first element is less than or equal to the second
//
// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// Nilf asserts that the specified object is nil.
//
// assert.Nilf(t, err, "error message %s", "formatted")
@ -444,6 +513,19 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
// Samef asserts that two pointers reference the same object.
//
// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Subsetf asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...).
//

View File

@ -215,6 +215,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
return Errorf(a.t, err, msg, args...)
}
// Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
}
// Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
}
// Exactly asserts that two objects are equal in value and type.
//
// a.Exactly(int32(123), int64(123))
@ -303,6 +325,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b
return FileExistsf(a.t, path, msg, args...)
}
// Greater asserts that the first element is greater than the second
//
// a.Greater(2, 1)
// a.Greater(float64(2), float64(1))
// a.Greater("b", "a")
func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Greater(a.t, e1, e2, msgAndArgs...)
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
// a.GreaterOrEqual(2, 1)
// a.GreaterOrEqual(2, 2)
// a.GreaterOrEqual("b", "a")
// a.GreaterOrEqual("b", "b")
func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
}
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
//
// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return GreaterOrEqualf(a.t, e1, e2, msg, args...)
}
// Greaterf asserts that the first element is greater than the second
//
// a.Greaterf(2, 1, "error message %s", "formatted")
// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
// a.Greaterf("b", "a", "error message %s", "formatted")
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Greaterf(a.t, e1, e2, msg, args...)
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
@ -567,6 +639,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
return JSONEqf(a.t, expected, actual, msg, args...)
}
// YAMLEq asserts that two YAML strings are equivalent.
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return YAMLEq(a.t, expected, actual, msgAndArgs...)
}
// YAMLEqf asserts that two YAML strings are equivalent.
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return YAMLEqf(a.t, expected, actual, msg, args...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
@ -589,6 +677,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
return Lenf(a.t, object, length, msg, args...)
}
// Less asserts that the first element is less than the second
//
// a.Less(1, 2)
// a.Less(float64(1), float64(2))
// a.Less("a", "b")
func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Less(a.t, e1, e2, msgAndArgs...)
}
// LessOrEqual asserts that the first element is less than or equal to the second
//
// a.LessOrEqual(1, 2)
// a.LessOrEqual(2, 2)
// a.LessOrEqual("a", "b")
// a.LessOrEqual("b", "b")
func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return LessOrEqual(a.t, e1, e2, msgAndArgs...)
}
// LessOrEqualf asserts that the first element is less than or equal to the second
//
// a.LessOrEqualf(1, 2, "error message %s", "formatted")
// a.LessOrEqualf(2, 2, "error message %s", "formatted")
// a.LessOrEqualf("a", "b", "error message %s", "formatted")
// a.LessOrEqualf("b", "b", "error message %s", "formatted")
func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return LessOrEqualf(a.t, e1, e2, msg, args...)
}
// Lessf asserts that the first element is less than the second
//
// a.Lessf(1, 2, "error message %s", "formatted")
// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
// a.Lessf("a", "b", "error message %s", "formatted")
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Lessf(a.t, e1, e2, msg, args...)
}
// Nil asserts that the specified object is nil.
//
// a.Nil(err)
@ -877,6 +1015,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
return Regexpf(a.t, rx, str, msg, args...)
}
// Same asserts that two pointers reference the same object.
//
// a.Same(ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Same(a.t, expected, actual, msgAndArgs...)
}
// Samef asserts that two pointers reference the same object.
//
// a.Samef(ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Samef(a.t, expected, actual, msg, args...)
}
// Subset asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...).
//

View File

@ -0,0 +1,309 @@
package assert
import (
"fmt"
"reflect"
)
func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
switch kind {
case reflect.Int:
{
intobj1 := obj1.(int)
intobj2 := obj2.(int)
if intobj1 > intobj2 {
return -1, true
}
if intobj1 == intobj2 {
return 0, true
}
if intobj1 < intobj2 {
return 1, true
}
}
case reflect.Int8:
{
int8obj1 := obj1.(int8)
int8obj2 := obj2.(int8)
if int8obj1 > int8obj2 {
return -1, true
}
if int8obj1 == int8obj2 {
return 0, true
}
if int8obj1 < int8obj2 {
return 1, true
}
}
case reflect.Int16:
{
int16obj1 := obj1.(int16)
int16obj2 := obj2.(int16)
if int16obj1 > int16obj2 {
return -1, true
}
if int16obj1 == int16obj2 {
return 0, true
}
if int16obj1 < int16obj2 {
return 1, true
}
}
case reflect.Int32:
{
int32obj1 := obj1.(int32)
int32obj2 := obj2.(int32)
if int32obj1 > int32obj2 {
return -1, true
}
if int32obj1 == int32obj2 {
return 0, true
}
if int32obj1 < int32obj2 {
return 1, true
}
}
case reflect.Int64:
{
int64obj1 := obj1.(int64)
int64obj2 := obj2.(int64)
if int64obj1 > int64obj2 {
return -1, true
}
if int64obj1 == int64obj2 {
return 0, true
}
if int64obj1 < int64obj2 {
return 1, true
}
}
case reflect.Uint:
{
uintobj1 := obj1.(uint)
uintobj2 := obj2.(uint)
if uintobj1 > uintobj2 {
return -1, true
}
if uintobj1 == uintobj2 {
return 0, true
}
if uintobj1 < uintobj2 {
return 1, true
}
}
case reflect.Uint8:
{
uint8obj1 := obj1.(uint8)
uint8obj2 := obj2.(uint8)
if uint8obj1 > uint8obj2 {
return -1, true
}
if uint8obj1 == uint8obj2 {
return 0, true
}
if uint8obj1 < uint8obj2 {
return 1, true
}
}
case reflect.Uint16:
{
uint16obj1 := obj1.(uint16)
uint16obj2 := obj2.(uint16)
if uint16obj1 > uint16obj2 {
return -1, true
}
if uint16obj1 == uint16obj2 {
return 0, true
}
if uint16obj1 < uint16obj2 {
return 1, true
}
}
case reflect.Uint32:
{
uint32obj1 := obj1.(uint32)
uint32obj2 := obj2.(uint32)
if uint32obj1 > uint32obj2 {
return -1, true
}
if uint32obj1 == uint32obj2 {
return 0, true
}
if uint32obj1 < uint32obj2 {
return 1, true
}
}
case reflect.Uint64:
{
uint64obj1 := obj1.(uint64)
uint64obj2 := obj2.(uint64)
if uint64obj1 > uint64obj2 {
return -1, true
}
if uint64obj1 == uint64obj2 {
return 0, true
}
if uint64obj1 < uint64obj2 {
return 1, true
}
}
case reflect.Float32:
{
float32obj1 := obj1.(float32)
float32obj2 := obj2.(float32)
if float32obj1 > float32obj2 {
return -1, true
}
if float32obj1 == float32obj2 {
return 0, true
}
if float32obj1 < float32obj2 {
return 1, true
}
}
case reflect.Float64:
{
float64obj1 := obj1.(float64)
float64obj2 := obj2.(float64)
if float64obj1 > float64obj2 {
return -1, true
}
if float64obj1 == float64obj2 {
return 0, true
}
if float64obj1 < float64obj2 {
return 1, true
}
}
case reflect.String:
{
stringobj1 := obj1.(string)
stringobj2 := obj2.(string)
if stringobj1 > stringobj2 {
return -1, true
}
if stringobj1 == stringobj2 {
return 0, true
}
if stringobj1 < stringobj2 {
return 1, true
}
}
}
return 0, false
}
// Greater asserts that the first element is greater than the second
//
// assert.Greater(t, 2, 1)
// assert.Greater(t, float64(2), float64(1))
// assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != -1 {
return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...)
}
return true
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
// assert.GreaterOrEqual(t, 2, 1)
// assert.GreaterOrEqual(t, 2, 2)
// assert.GreaterOrEqual(t, "b", "a")
// assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != -1 && res != 0 {
return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...)
}
return true
}
// Less asserts that the first element is less than the second
//
// assert.Less(t, 1, 2)
// assert.Less(t, float64(1), float64(2))
// assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != 1 {
return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...)
}
return true
}
// LessOrEqual asserts that the first element is less than or equal to the second
//
// assert.LessOrEqual(t, 1, 2)
// assert.LessOrEqual(t, 2, 2)
// assert.LessOrEqual(t, "a", "b")
// assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != 1 && res != 0 {
return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...)
}
return true
}

View File

@ -18,6 +18,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
yaml "gopkg.in/yaml.v2"
)
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
@ -350,6 +351,37 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
}
// Same asserts that two pointers reference the same object.
//
// assert.Same(t, ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
}
expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
if expectedType != actualType {
return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
expectedType, actualType), msgAndArgs...)
}
if expected != actual {
return Fail(t, fmt.Sprintf("Not same: \n"+
"expected: %p %#v\n"+
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
}
return true
}
// formatUnequalValues takes two values of arbitrary types and returns string
// representations appropriate to be presented to the user.
//
@ -479,14 +511,14 @@ func isEmpty(object interface{}) bool {
// collection types are empty when they have no element
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
// pointers are empty if nil or if the value they point to is empty
// pointers are empty if nil or if the value they point to is empty
case reflect.Ptr:
if objValue.IsNil() {
return true
}
deref := objValue.Elem().Interface()
return isEmpty(deref)
// for all other types, compare against the zero value
// for all other types, compare against the zero value
default:
zero := reflect.Zero(objValue.Type())
return reflect.DeepEqual(object, zero.Interface())
@ -629,7 +661,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
func includeElement(list interface{}, element interface{}) (ok, found bool) {
listValue := reflect.ValueOf(list)
elementValue := reflect.ValueOf(element)
listKind := reflect.TypeOf(list).Kind()
defer func() {
if e := recover(); e != nil {
ok = false
@ -637,11 +669,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
}
}()
if reflect.TypeOf(list).Kind() == reflect.String {
if listKind == reflect.String {
elementValue := reflect.ValueOf(element)
return true, strings.Contains(listValue.String(), elementValue.String())
}
if reflect.TypeOf(list).Kind() == reflect.Map {
if listKind == reflect.Map {
mapKeys := listValue.MapKeys()
for i := 0; i < len(mapKeys); i++ {
if ObjectsAreEqual(mapKeys[i].Interface(), element) {
@ -1337,6 +1370,24 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
}
// YAMLEq asserts that two YAML strings are equivalent.
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
}
return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
}
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
t := reflect.TypeOf(v)
k := t.Kind()
@ -1371,8 +1422,8 @@ func diff(expected interface{}, actual interface{}) string {
e = spewConfig.Sdump(expected)
a = spewConfig.Sdump(actual)
} else {
e = expected.(string)
a = actual.(string)
e = reflect.ValueOf(expected).String()
a = reflect.ValueOf(actual).String()
}
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
@ -1414,3 +1465,34 @@ var spewConfig = spew.ConfigState{
type tHelper interface {
Helper()
}
// Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
timer := time.NewTimer(waitFor)
ticker := time.NewTicker(tick)
checkPassed := make(chan bool)
defer timer.Stop()
defer ticker.Stop()
defer close(checkPassed)
for {
select {
case <-timer.C:
return Fail(t, "Condition never satisfied", msgAndArgs...)
case result := <-checkPassed:
if result {
return true
}
case <-ticker.C:
go func() {
checkPassed <- condition()
}()
}
}
}

2
vendor/github.com/tiramiseb/go-gandi/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
/cmd/gandi
.idea

7
vendor/github.com/tiramiseb/go-gandi/LICENSE generated vendored Normal file
View File

@ -0,0 +1,7 @@
Copyright 2017 Sébastien Maccagnoni
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.

13
vendor/github.com/tiramiseb/go-gandi/README.md generated vendored Normal file
View File

@ -0,0 +1,13 @@
Gandi Go library
================
WIP: migrating from https://github.com/tiramiseb/go-gandi-livedns
cmd not working, fix needed
[![GoDoc](https://godoc.org/github.com/tiramiseb/go-gandi?status.svg)](https://godoc.org/github.com/tiramiseb/go-gandi)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/tiramiseb/go-gandi/master/LICENSE)
This library interacts with [Gandi's API](https://api.gandi.net/docs/), to manage Gandi services. This API returns some data as HTTP headers, please note those are ignored by this library.
A simple CLI is also shipped with this library. It returns responses to the requests in JSON.

166
vendor/github.com/tiramiseb/go-gandi/domain/domain.go generated vendored Normal file
View File

@ -0,0 +1,166 @@
package domain
import (
"time"
"github.com/tiramiseb/go-gandi/internal/client"
)
type Domain struct {
client client.Gandi
}
func New(apikey string, sharingid string, debug bool) *Domain {
client := client.New(apikey, sharingid, debug)
client.SetEndpoint("domain/")
return &Domain{client: *client}
}
func NewFromClient(g client.Gandi) *Domain {
g.SetEndpoint("domain/")
return &Domain{client: g}
}
// Contact represents a contact associated with a domain
type Contact struct {
Country string `json:"country"`
Email string `json:"email"`
Family string `json:"family"`
Given string `json:"given"`
StreetAddr string `json:"streetaddr"`
ContactType int `json:"type"`
BrandNumber string `json:"brand_number,omitempty"`
City string `json:"city,omitempty"`
DataObfuscated *bool `json:"data_obfuscated,omitempty"`
Fax string `json:"fax,omitempty"`
Language string `json:"lang,omitempty"`
MailObfuscated *bool `json:"mail_obfuscated,omitempty"`
Mobile string `json:"mobile,omitempty"`
OrgName string `json:"orgname,omitempty"`
Phone string `json:"phone,omitempty"`
Siren string `json:"siren,omitempty"`
State string `json:"state,omitempty"`
Validation string `json:"validation,omitempty"`
Zip string `json:"zip,omitempty"`
}
// DomainResponseDates represents all the dates associated with a domain
type DomainResponseDates struct {
RegistryCreatedAt time.Time `json:"registry_created_at"`
UpdatedAt time.Time `json:"updated_at"`
AuthInfoExpiresAt time.Time `json:"authinfo_expires_at,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
DeletesAt time.Time `json:"deletes_at,omitempty"`
HoldBeginsAt time.Time `json:"hold_begins_at,omitempty"`
HoldEndsAt time.Time `json:"hold_ends_at,omitempty"`
PendingDeleteEndsAt time.Time `json:"pending_delete_ends_at,omitempty"`
RegistryEndsAt time.Time `json:"registry_ends_at,omitempty"`
RenewBeginsAt time.Time `json:"renew_begins_at,omitempty"`
RenewEndsAt time.Time `json:"renew_ends_at,omitempty"`
}
// NameServerConfig represents the name server configuration for a domain
type NameServerConfig struct {
Current string `json:"current"`
Hosts []string `json:"hosts,omitempty"`
}
// DomainListResponse is the response object returned by listing domains
type DomainListResponse struct {
AutoRenew *bool `json:"autorenew"`
Dates DomainResponseDates `json:"dates"`
DomainOwner string `json:"domain_owner"`
FQDN string `json:"fqdn"`
FQDNUnicode string `json:"fqdn_unicode"`
Href string `json:"href"`
ID string `json:"id"`
NameServer NameServerConfig `json:"nameserver"`
OrgaOwner string `json:"orga_owner"`
Owner string `json:"owner"`
Status []string `json:"status"`
TLD string `json:"tld"`
SharingID string `json:"sharing_id,omitempty"`
Tags []string `json:"tags,omitempty"`
}
// AutoRenew is the auto renewal information for the domain
type AutoRenew struct {
Href string `json:"href"`
Dates []time.Time `json:"dates,omitempty"`
Duration int `json:"duration,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
OrgID string `json:"org_id,omitempty"`
}
// The Organisation that owns the domain
type SharingSpace struct {
ID string `json:"id"`
Name string `json:"name"`
}
// DomainResponse describes a single domain
type DomainResponse struct {
AutoRenew AutoRenew `json:"autorenew"`
CanTLDLock *bool `json:"can_tld_lock"`
Contacts DomainContacts `json:"contacts"`
Dates DomainResponseDates `json:"dates"`
FQDN string `json:"fqdn"`
FQDNUnicode string `json:"fqdn_unicode"`
Href string `json:"href"`
Nameservers []string `json:"nameservers,omitempty"`
Services []string `json:"services"`
SharingSpace SharingSpace `json:"sharing_space"`
Status []string `json:"status"`
TLD string `json:"tld"`
AuthInfo string `json:"authinfo,omitempty"`
ID string `json:"id,omitempty"`
SharingID string `json:"sharing_id,omitempty"`
Tags []string `json:"tags,omitempty"`
TrusteeRoles []string `json:"trustee_roles,omitempty"`
}
// DomainContacts is the set of contacts associated with a Domain
type DomainContacts struct {
Admin Contact `json:"admin,omitempty"`
Bill Contact `json:"bill,omitempty"`
Owner Contact `json:"owner,omitempty"`
Tech Contact `json:"tech,omitempty"`
}
// Nameservers represents a list of nameservers
type Nameservers struct {
Nameservers []string `json:"nameservers,omitempty"`
}
func (g *Domain) ListDomains() (domains []DomainListResponse, err error) {
_, err = g.client.Get("domains", nil, &domains)
return
}
func (g *Domain) GetDomain(domain string) (domainResponse DomainResponse, err error) {
_, err = g.client.Get("domains/"+domain, nil, &domainResponse)
return
}
func (g *Domain) GetNameServers(domain string) (nameservers []string, err error) {
_, err = g.client.Get("domains/"+domain+"/nameservers", nil, &nameservers)
return
}
// UpdateNameServers sets the list of the nameservers for a domain
func (g *Domain) UpdateNameServers(domain string, ns []string) (err error) {
_, err = g.client.Put("domains/"+domain+"/nameservers", Nameservers{ns}, nil)
return
}
// GetContacts returns the contact objects for a domain
func (g *Domain) GetContacts(domain string) (contacts DomainContacts, err error) {
_, err = g.client.Get("domains/"+domain+"/contacts", nil, &contacts)
return
}
// SetContacts returns the contact objects for a domain
func (g *Domain) SetContacts(domain string, contacts DomainContacts) (err error) {
_, err = g.client.Patch("domains/"+domain+"/contacts", contacts, nil)
return
}

19
vendor/github.com/tiramiseb/go-gandi/gandi.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
package gandi
import (
"github.com/tiramiseb/go-gandi/domain"
"github.com/tiramiseb/go-gandi/livedns"
)
type Config struct {
SharingID string
Debug bool
}
func NewDomainClient(apikey string, config Config) *domain.Domain {
return domain.New(apikey, config.SharingID, config.Debug)
}
func NewLiveDNSClient(apikey string, config Config) *livedns.LiveDNS {
return livedns.New(apikey, config.SharingID, config.Debug)
}

9
vendor/github.com/tiramiseb/go-gandi/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module github.com/tiramiseb/go-gandi
go 1.13
require (
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
)

13
vendor/github.com/tiramiseb/go-gandi/go.sum generated vendored Normal file
View File

@ -0,0 +1,13 @@
github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tiramiseb/go-gandi-livedns v0.0.0-20200115114823-77cf002f44da h1:8yQIyyxIjektbd5aNbi9BZadosFjU3Xg3imyTS6fUcM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -0,0 +1,157 @@
package client
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"strings"
)
const (
gandiEndpoint = "https://api.gandi.net/v5/"
)
// Gandi is the handle used to interact with the Gandi API
type Gandi struct {
apikey string
endpoint string
sharingID string
debug bool
}
// New instantiates a new Gandi instance
func New(apikey string, sharingID string, debug bool) *Gandi {
return &Gandi{apikey: apikey, endpoint: gandiEndpoint, sharingID: sharingID, debug: debug}
}
func (g *Gandi) SetEndpoint(endpoint string) {
g.endpoint = gandiEndpoint + endpoint
}
func (g *Gandi) Get(path string, params, recipient interface{}) (http.Header, error) {
return g.askGandi(http.MethodGet, path, params, recipient)
}
func (g *Gandi) Post(path string, params, recipient interface{}) (http.Header, error) {
return g.askGandi(http.MethodPost, path, params, recipient)
}
func (g *Gandi) Patch(path string, params, recipient interface{}) (http.Header, error) {
return g.askGandi(http.MethodPatch, path, params, recipient)
}
func (g *Gandi) Delete(path string, params, recipient interface{}) (http.Header, error) {
return g.askGandi(http.MethodDelete, path, params, recipient)
}
func (g *Gandi) Put(path string, params, recipient interface{}) (http.Header, error) {
return g.askGandi(http.MethodPut, path, params, recipient)
}
func (g *Gandi) askGandi(method, path string, params, recipient interface{}) (http.Header, error) {
resp, err := g.doAskGandi(method, path, params, nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
decoder.Decode(recipient)
return resp.Header, nil
}
func (g *Gandi) GetBytes(path string, params interface{}) (http.Header, []byte, error) {
headers := [][2]string{
{"Accept", "text/plain"},
}
resp, err := g.doAskGandi(http.MethodGet, path, params, headers)
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
return resp.Header, content, err
}
func (g *Gandi) doAskGandi(method, path string, p interface{}, extraHeaders [][2]string) (*http.Response, error) {
var (
err error
req *http.Request
)
params, err := json.Marshal(p)
if err != nil {
return nil, err
}
client := &http.Client{}
suffix := ""
if len(g.sharingID) != 0 {
suffix += "?sharing_id=" + g.sharingID
}
if params != nil && string(params) != "null" {
req, err = http.NewRequest(method, g.endpoint+path+suffix, bytes.NewReader(params))
} else {
req, err = http.NewRequest(method, g.endpoint+path+suffix, nil)
}
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Apikey "+g.apikey)
req.Header.Add("Content-Type", "application/json")
for _, header := range extraHeaders {
req.Header.Add(header[0], header[1])
}
if g.debug {
dump, _ := httputil.DumpRequestOut(req, true)
fmt.Println("=======================================\nREQUEST:")
fmt.Println(string(dump))
}
resp, err := client.Do(req)
if err != nil {
return resp, err
}
if g.debug {
dump, _ := httputil.DumpResponse(resp, true)
fmt.Println("=======================================\nREQUEST:")
fmt.Println(string(dump))
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
defer resp.Body.Close()
var message StandardResponse
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
decoder.Decode(&message)
if message.Message != "" {
err = fmt.Errorf("%d: %s", resp.StatusCode, message.Message)
} else if len(message.Errors) > 0 {
var errors []string
for _, oneError := range message.Errors {
errors = append(errors, fmt.Sprintf("%s: %s", oneError.Name, oneError.Description))
}
err = fmt.Errorf(strings.Join(errors, ", "))
} else {
err = fmt.Errorf("%d", resp.StatusCode)
}
}
return resp, err
}
// StandardResponse is a standard response
type StandardResponse struct {
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
UUID string `json:"uuid,omitempty"`
Object string `json:"object,omitempty"`
Cause string `json:"cause,omitempty"`
Status string `json:"status,omitempty"`
Errors []StandardError `json:"errors,omitempty"`
}
// StandardError is embedded in a standard error
type StandardError struct {
Location string `json:"location"`
Name string `json:"name"`
Description string `json:"description"`
}

76
vendor/github.com/tiramiseb/go-gandi/livedns/axfr.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package livedns
// Tsig contains tsig data (no kidding!)
type Tsig struct {
KeyName string `json:"key_name, omitempty"`
Secret string `json:"secret,omitempty"`
UUID string `json:"uuid,omitempty"`
AxfrTsigURL string `json:"axfr_tsig_url,omitempty"`
ConfigSamples interface{} `json:"config_samples,omitempty"`
}
// ListTsigs lists all tsigs
func (g *LiveDNS) ListTsigs() (tsigs []Tsig, err error) {
_, err = g.client.Get("axfr/tsig", nil, &tsigs)
return
}
// GetTsig lists more tsig details
func (g *LiveDNS) GetTsig(uuid string) (tsig Tsig, err error) {
_, err = g.client.Get("axfr/tsig/"+uuid, nil, &tsig)
return
}
// GetTsigBIND shows a BIND nameserver config, and includes the nameservers available for zone transfers
func (g *LiveDNS) GetTsigBIND(uuid string) ([]byte, error) {
_, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/bind", nil)
return content, err
}
// GetTsigPowerDNS shows a PowerDNS nameserver config, and includes the nameservers available for zone transfers
func (g *LiveDNS) GetTsigPowerDNS(uuid string) ([]byte, error) {
_, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/powerdns", nil)
return content, err
}
// GetTsigNSD shows a NSD nameserver config, and includes the nameservers available for zone transfers
func (g *LiveDNS) GetTsigNSD(uuid string) ([]byte, error) {
_, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/nsd", nil)
return content, err
}
// GetTsigKnot shows a Knot nameserver config, and includes the nameservers available for zone transfers
func (g *LiveDNS) GetTsigKnot(uuid string) ([]byte, error) {
_, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/knot", nil)
return content, err
}
// CreateTsig creates a tsig
func (g *LiveDNS) CreateTsig() (tsig Tsig, err error) {
_, err = g.client.Post("axfr/tsig", nil, &tsig)
return
}
// AddTsigToDomain adds a tsig to a domain
func (g *LiveDNS) AddTsigToDomain(fqdn, uuid string) (err error) {
_, err = g.client.Put("domains/"+fqdn+"/axfr/tsig/"+uuid, nil, nil)
return
}
// AddSlaveToDomain adds a slave to a domain
func (g *LiveDNS) AddSlaveToDomain(fqdn, host string) (err error) {
_, err = g.client.Put("domains/"+fqdn+"/axfr/slaves/"+host, nil, nil)
return
}
// ListSlavesInDomain lists slaves in a domain
func (g *LiveDNS) ListSlavesInDomain(fqdn string) (slaves []string, err error) {
_, err = g.client.Get("domains/"+fqdn+"/axfr/slaves", nil, &slaves)
return
}
// DelSlaveFromDomain removes a slave from a domain
func (g *LiveDNS) DelSlaveFromDomain(fqdn, host string) (err error) {
_, err = g.client.Delete("domains/"+fqdn+"/axfr/slaves/"+host, nil, nil)
return
}

101
vendor/github.com/tiramiseb/go-gandi/livedns/domain.go generated vendored Normal file
View File

@ -0,0 +1,101 @@
package livedns
import "github.com/tiramiseb/go-gandi/internal/client"
// Domain represents a DNS domain
type Domain struct {
FQDN string `json:"fqdn,omitempty"`
DomainHref string `json:"domain_href,omitempty"`
DomainKeysHref string `json:"domain_keys_href,omitempty"`
DomainRecordsHref string `json:"domain_records_href,omitempty"`
ZoneUUID string `json:"zone_uuid,omitempty"`
ZoneHref string `json:"zone_href,omitempty"`
ZoneRecordsHref string `json:"zone_records_href,omitempty"`
}
// SigningKey holds data about a DNSSEC signing key
type SigningKey struct {
Status string `json:"status,omitempty"`
UUID string `json:"uuid,omitempty"`
Algorithm int `json:"algorithm,omitempty"`
Deleted *bool `json:"deleted"`
AlgorithmName string `json:"algorithm_name,omitempty"`
FQDN string `json:"fqdn,omitempty"`
Flags int `json:"flags,omitempty"`
DS string `json:"ds,omitempty"`
KeyHref string `json:"key_href,omitempty"`
}
type zone struct {
TTL int `json:"ttl"`
}
type createDomainRequest struct {
FQDN string `json:"fqdn"`
Zone zone `json:"zone,omitempty"`
}
type UpdateDomainRequest struct {
AutomaticSnapshots *bool `json:"automatic_snapshots,omitempty"`
}
// ListDomains lists all domains
func (g *LiveDNS) ListDomains() (domains []Domain, err error) {
_, err = g.client.Get("domains", nil, &domains)
return
}
// CreateDomain adds a domain to a zone
func (g *LiveDNS) CreateDomain(fqdn string, ttl int) (response client.StandardResponse, err error) {
_, err = g.client.Post("domains", createDomainRequest{FQDN: fqdn, Zone: zone{TTL: ttl}}, &response)
return
}
// GetDomain returns a domain
func (g *LiveDNS) GetDomain(fqdn string) (domain Domain, err error) {
_, err = g.client.Get("domains/"+fqdn, nil, &domain)
return
}
// ChangeAssociatedZone changes the zone associated to a domain
func (g *LiveDNS) UpdateDomain(fqdn string, details UpdateDomainRequest) (response client.StandardResponse, err error) {
_, err = g.client.Patch("domains/"+fqdn, details, &response)
return
}
// DetachDomain detaches a domain from the zone it is attached to
func (g *LiveDNS) DetachDomain(fqdn string) (err error) {
_, err = g.client.Delete("domains/"+fqdn, nil, nil)
return
}
// SignDomain creates a DNSKEY and asks Gandi servers to automatically sign the domain
func (g *LiveDNS) SignDomain(fqdn string) (response client.StandardResponse, err error) {
f := SigningKey{Flags: 257}
_, err = g.client.Post("domains/"+fqdn+"/keys", f, &response)
return
}
// GetDomainKeys returns data about the signing keys created for a domain
func (g *LiveDNS) GetDomainKeys(fqdn string) (keys []SigningKey, err error) {
_, err = g.client.Get("domains/"+fqdn+"/keys", nil, &keys)
return
}
// DeleteDomainKey deletes a signing key from a domain
func (g *LiveDNS) DeleteDomainKey(fqdn, uuid string) (err error) {
_, err = g.client.Delete("domains/"+fqdn+"/keys/"+uuid, nil, nil)
return
}
// UpdateDomainKey updates a signing key for a domain (only the deleted status, actually...)
func (g *LiveDNS) UpdateDomainKey(fqdn, uuid string, deleted bool) (err error) {
_, err = g.client.Put("domains/"+fqdn+"/keys/"+uuid, SigningKey{Deleted: &deleted}, nil)
return
}
// GetDomainNS returns the list of the nameservers for a domain
func (g *LiveDNS) GetDomainNS(fqdn string) (ns []string, err error) {
_, err = g.client.Get("nameservers/"+fqdn, nil, &ns)
return
}

View File

@ -0,0 +1,97 @@
package livedns
import "github.com/tiramiseb/go-gandi/internal/client"
// DomainRecord represents a DNS Record
type DomainRecord struct {
RrsetType string `json:"rrset_type,omitempty"`
RrsetTTL int `json:"rrset_ttl,omitempty"`
RrsetName string `json:"rrset_name,omitempty"`
RrsetHref string `json:"rrset_href,omitempty"`
RrsetValues []string `json:"rrset_values,omitempty"`
}
// ListDomainRecords lists all records in the zone associated with a domain
func (g *LiveDNS) ListDomainRecords(fqdn string) (records []DomainRecord, err error) {
_, err = g.client.Get("domains/"+fqdn+"/records", nil, &records)
return
}
// ListDomainRecordsAsText lists all records in a zone and returns them as a text file
// ... and by text, I mean a slice of bytes
func (g *LiveDNS) ListDomainRecordsAsText(uuid string) ([]byte, error) {
_, content, err := g.client.GetBytes("domains/"+uuid+"/records", nil)
return content, err
}
// ListDomainRecordsWithName lists all records with a specific name in a zone
func (g *LiveDNS) ListDomainRecordsWithName(fqdn, name string) (records []DomainRecord, err error) {
_, err = g.client.Get("domains/"+fqdn+"/records/"+name, nil, &records)
return
}
// GetDomainRecordWithNameAndType gets the record with specific name and type in the zone attached to the domain
func (g *LiveDNS) GetDomainRecordWithNameAndType(fqdn, name, recordtype string) (record DomainRecord, err error) {
_, err = g.client.Get("domains/"+fqdn+"/records/"+name+"/"+recordtype, nil, &record)
return
}
// CreateDomainRecord creates a record in the zone attached to a domain
func (g *LiveDNS) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response client.StandardResponse, err error) {
_, err = g.client.Post("domains/"+fqdn+"/records",
DomainRecord{
RrsetType: recordtype,
RrsetTTL: ttl,
RrsetName: name,
RrsetValues: values,
},
&response)
return
}
type itemsPrefixForZoneRecords struct {
Items []DomainRecord `json:"items"`
}
// ChangeDomainRecords changes all records in the zone attached to a domain
func (g *LiveDNS) ChangeDomainRecords(fqdn string, records []DomainRecord) (response client.StandardResponse, err error) {
prefixedRecords := itemsPrefixForZoneRecords{Items: records}
_, err = g.client.Put("domains/"+fqdn+"/records", prefixedRecords, &response)
return
}
// ChangeDomainRecordsWithName changes all records with the given name in the zone attached to the domain
func (g *LiveDNS) ChangeDomainRecordsWithName(fqdn, name string, records []DomainRecord) (response client.StandardResponse, err error) {
prefixedRecords := itemsPrefixForZoneRecords{Items: records}
_, err = g.client.Put("domains/"+fqdn+"/records/"+name, prefixedRecords, &response)
return
}
// ChangeDomainRecordWithNameAndType changes the record with the given name and the given type in the zone attached to a domain
func (g *LiveDNS) ChangeDomainRecordWithNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response client.StandardResponse, err error) {
_, err = g.client.Put("domains/"+fqdn+"/records/"+name+"/"+recordtype,
DomainRecord{
RrsetTTL: ttl,
RrsetValues: values,
},
&response)
return
}
// DeleteAllDomainRecords deletes all records in the zone attached to a domain
func (g *LiveDNS) DeleteAllDomainRecords(fqdn string) (err error) {
_, err = g.client.Delete("domains/"+fqdn+"/records", nil, nil)
return
}
// DeleteDomainRecords deletes all records with the given name in the zone attached to a domain
func (g *LiveDNS) DeleteDomainRecords(fqdn, name string) (err error) {
_, err = g.client.Delete("domains/"+fqdn+"/records/"+name, nil, nil)
return
}
// DeleteDomainRecord deletes the record with the given name and the given type in the zone attached to a domain
func (g *LiveDNS) DeleteDomainRecord(fqdn, name, recordtype string) (err error) {
_, err = g.client.Delete("domains/"+fqdn+"/records/"+name+"/"+recordtype, nil, nil)
return
}

View File

@ -0,0 +1,20 @@
package livedns
import (
"github.com/tiramiseb/go-gandi/internal/client"
)
type LiveDNS struct {
client client.Gandi
}
func New(apikey string, sharingid string, debug bool) *LiveDNS {
client := client.New(apikey, sharingid, debug)
client.SetEndpoint("livedns/")
return &LiveDNS{client: *client}
}
func NewFromClient(g client.Gandi) *LiveDNS {
g.SetEndpoint("livedns/")
return &LiveDNS{client: g}
}

View File

@ -0,0 +1,29 @@
package livedns
import "github.com/tiramiseb/go-gandi/internal/client"
// Snapshot represents a zone snapshot
type Snapshot struct {
UUID string `json:"uuid,omitempty"`
DateCreated string `json:"date_created,omitempty"`
ZoneUUID string `json:"zone_uuid,omitempty"`
ZoneData []DomainRecord `json:"zone_data,omitempty"`
}
// ListSnapshots lists all domains
func (g *LiveDNS) ListSnapshots(fqdn string) (snapshots []Snapshot, err error) {
_, err = g.client.Get("domains/"+fqdn+"/snapshots", nil, &snapshots)
return
}
// CreateSnapshot creates a domain
func (g *LiveDNS) CreateSnapshot(fqdn string) (response client.StandardResponse, err error) {
_, err = g.client.Post("domains/"+fqdn+"/snapshots", nil, &response)
return
}
// GetSnapshot returns a domain
func (g *LiveDNS) GetSnapshot(fqdn, snapUUID string) (snapshot Snapshot, err error) {
_, err = g.client.Get("domains/"+fqdn+"/snapshots/"+snapUUID, nil, &snapshot)
return
}