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