func loadConfig(cfgJSON *extapi.JSON) (ovhDNSProviderConfig, error) {
	cfg := ovhDNSProviderConfig{}
	if cfgJSON == nil {
		return cfg, nil
	}
	if err := json.Unmarshal(cfgJSON.Raw, &cfg); err != nil {
		return cfg, fmt.Errorf("error decoding OVH config: %v", err)
	}
	return cfg, nil
}
loadConfig is a small helper function that decodes JSON configuration into
the typed config struct.
package main
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	corev1 "k8s.io/api/core/v1"
	extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"github.com/jetstack/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
	"github.com/jetstack/cert-manager/pkg/acme/webhook/cmd"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util"
	"github.com/ovh/go-ovh/ovh"
)
var GroupName = os.Getenv("GROUP_NAME")
func main() {
	if GroupName == "" {
		panic("GROUP_NAME must be specified")
	}
	cmd.RunWebhookServer(GroupName,
		&ovhDNSProviderSolver{},
	)
}
type ovhDNSProviderSolver struct {
	client *kubernetes.Clientset
}
type ovhDNSProviderConfig struct {
	Endpoint             string                   `json:"endpoint"`
	ApplicationKey       string                   `json:"applicationKey"`
	ApplicationSecretRef corev1.SecretKeySelector `json:"applicationSecretRef"`
	ConsumerKey          string                   `json:"consumerKey"`
}
type ovhZoneStatus struct {
	IsDeployed bool `json:"isDeployed"`
}
type ovhZoneRecord struct {
	Id        int64  `json:"id,omitempty"`
	FieldType string `json:"fieldType"`
	SubDomain string `json:"subDomain"`
	Target    string `json:"target"`
	TTL       int    `json:"ttl,omitempty"`
}
func (s *ovhDNSProviderSolver) Name() string {
	return "ovh"
}
func (s *ovhDNSProviderSolver) validate(cfg *ovhDNSProviderConfig, allowAmbientCredentials bool) error {
	if allowAmbientCredentials {
		return nil
	}
	if cfg.Endpoint == "" {
		return errors.New("no endpoint provided in OVH config")
	}
	if cfg.ApplicationKey == "" {
		return errors.New("no application key provided in OVH config")
	}
	if cfg.ApplicationSecretRef.Name == "" {
		return errors.New("no application secret provided in OVH config")
	}
	if cfg.ConsumerKey == "" {
		return errors.New("no consumer key provided in OVH config")
	}
	return nil
}
func (s *ovhDNSProviderSolver) ovhClient(ch *v1alpha1.ChallengeRequest) (*ovh.Client, error) {
	cfg, err := loadConfig(ch.Config)
	if err != nil {
		return nil, err
	}
	err = s.validate(&cfg, ch.AllowAmbientCredentials)
	if err != nil {
		return nil, err
	}
	applicationSecret, err := s.secret(cfg.ApplicationSecretRef, ch.ResourceNamespace)
	if err != nil {
		return nil, err
	}
	return ovh.NewClient(cfg.Endpoint, cfg.ApplicationKey, applicationSecret, cfg.ConsumerKey)
}
func (s *ovhDNSProviderSolver) secret(ref corev1.SecretKeySelector, namespace string) (string, error) {
	if ref.Name == "" {
		return "", nil
	}
	secret, err := s.client.CoreV1().Secrets(namespace).Get(context.TODO(), ref.Name, metav1.GetOptions{})
	if err != nil {
		return "", err
	}
	bytes, ok := secret.Data[ref.Key]
	if !ok {
		return "", fmt.Errorf("key not found %q in secret '%s/%s'", ref.Key, namespace, ref.Name)
	}
	return string(bytes), nil
}
func (s *ovhDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
	ovhClient, err := s.ovhClient(ch)
	if err != nil {
		return err
	}
	domain := util.UnFqdn(ch.ResolvedZone)
	subDomain := getSubDomain(domain, ch.ResolvedFQDN)
	target := ch.Key
	return addTXTRecord(ovhClient, domain, subDomain, target)
}
func (s *ovhDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
	ovhClient, err := s.ovhClient(ch)
	if err != nil {
		return err
	}
	domain := util.UnFqdn(ch.ResolvedZone)
	subDomain := getSubDomain(domain, ch.ResolvedFQDN)
	target := ch.Key
	return removeTXTRecord(ovhClient, domain, subDomain, target)
}
func (s *ovhDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
	client, err := kubernetes.NewForConfig(kubeClientConfig)
	if err != nil {
		return err
	}
	s.client = client
	return nil
}