client.go raw

   1  package internal
   2  
   3  import (
   4  	"errors"
   5  	"fmt"
   6  	"net/http"
   7  	"net/url"
   8  
   9  	"github.com/gophercloud/gophercloud"
  10  	"github.com/gophercloud/gophercloud/openstack"
  11  )
  12  
  13  // Client VK client.
  14  type Client struct {
  15  	openstack     *gophercloud.ProviderClient
  16  	authOpts      gophercloud.AuthOptions
  17  	authenticated bool
  18  	baseURL       *url.URL
  19  }
  20  
  21  // NewClient creates a Client.
  22  func NewClient(endpoint string, authOpts gophercloud.AuthOptions) (*Client, error) {
  23  	err := validateAuthOptions(authOpts)
  24  	if err != nil {
  25  		return nil, err
  26  	}
  27  
  28  	openstackClient, err := openstack.NewClient(authOpts.IdentityEndpoint)
  29  	if err != nil {
  30  		return nil, fmt.Errorf("new client: %w", err)
  31  	}
  32  
  33  	baseURL, err := url.Parse(endpoint)
  34  	if err != nil {
  35  		return nil, fmt.Errorf("parse URL: %w", err)
  36  	}
  37  
  38  	return &Client{
  39  		openstack: openstackClient,
  40  		authOpts:  authOpts,
  41  		baseURL:   baseURL,
  42  	}, nil
  43  }
  44  
  45  func (c *Client) ListZones() ([]DNSZone, error) {
  46  	endpoint := c.baseURL.JoinPath("/")
  47  
  48  	var zones []DNSZone
  49  
  50  	opts := &gophercloud.RequestOpts{JSONResponse: &zones}
  51  
  52  	err := c.request(http.MethodGet, endpoint, opts)
  53  	if err != nil {
  54  		return nil, err
  55  	}
  56  
  57  	return zones, nil
  58  }
  59  
  60  func (c *Client) ListTXTRecords(zoneUUID string) ([]DNSTXTRecord, error) {
  61  	endpoint := c.baseURL.JoinPath(zoneUUID, "txt", "/")
  62  
  63  	var records []DNSTXTRecord
  64  
  65  	opts := &gophercloud.RequestOpts{JSONResponse: &records}
  66  
  67  	err := c.request(http.MethodGet, endpoint, opts)
  68  	if err != nil {
  69  		return nil, err
  70  	}
  71  
  72  	return records, nil
  73  }
  74  
  75  func (c *Client) CreateTXTRecord(zoneUUID string, record *DNSTXTRecord) error {
  76  	endpoint := c.baseURL.JoinPath(zoneUUID, "txt", "/")
  77  
  78  	opts := &gophercloud.RequestOpts{
  79  		JSONBody:     record,
  80  		JSONResponse: record,
  81  	}
  82  
  83  	return c.request(http.MethodPost, endpoint, opts)
  84  }
  85  
  86  func (c *Client) DeleteTXTRecord(zoneUUID, recordUUID string) error {
  87  	endpoint := c.baseURL.JoinPath(zoneUUID, "txt", recordUUID)
  88  
  89  	return c.request(http.MethodDelete, endpoint, &gophercloud.RequestOpts{})
  90  }
  91  
  92  func (c *Client) request(method string, endpoint *url.URL, options *gophercloud.RequestOpts) error {
  93  	if err := c.lazyAuth(); err != nil {
  94  		return fmt.Errorf("auth: %w", err)
  95  	}
  96  
  97  	_, err := c.openstack.Request(method, endpoint.String(), options)
  98  	if err != nil {
  99  		return fmt.Errorf("request: %w", err)
 100  	}
 101  
 102  	return nil
 103  }
 104  
 105  func (c *Client) lazyAuth() error {
 106  	if c.authenticated {
 107  		return nil
 108  	}
 109  
 110  	err := openstack.Authenticate(c.openstack, c.authOpts)
 111  	if err != nil {
 112  		return err
 113  	}
 114  
 115  	c.authenticated = true
 116  
 117  	return nil
 118  }
 119  
 120  func validateAuthOptions(opts gophercloud.AuthOptions) error {
 121  	if opts.TenantID == "" {
 122  		return errors.New("project id is missing in credentials information")
 123  	}
 124  
 125  	if opts.Username == "" {
 126  		return errors.New("username is missing in credentials information")
 127  	}
 128  
 129  	if opts.Password == "" {
 130  		return errors.New("password is missing in credentials information")
 131  	}
 132  
 133  	if opts.IdentityEndpoint == "" {
 134  		return errors.New("identity endpoint is missing in config")
 135  	}
 136  
 137  	if opts.DomainName == "" {
 138  		return errors.New("domain name is missing in config")
 139  	}
 140  
 141  	return nil
 142  }
 143